braintrust 3.26.0 → 3.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dev/dist/index.d.mts +519 -186
  2. package/dev/dist/index.d.ts +519 -186
  3. package/dev/dist/index.js +3727 -1526
  4. package/dev/dist/index.mjs +2815 -614
  5. package/dist/apply-auto-instrumentation.js +372 -261
  6. package/dist/apply-auto-instrumentation.mjs +171 -60
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +458 -61
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +5 -4
  9. package/dist/auto-instrumentations/bundler/next.cjs +460 -63
  10. package/dist/auto-instrumentations/bundler/next.mjs +6 -5
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +458 -61
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +5 -4
  13. package/dist/auto-instrumentations/bundler/vite.cjs +487 -62
  14. package/dist/auto-instrumentations/bundler/vite.mjs +34 -5
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +444 -61
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +458 -61
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +6 -5
  18. package/dist/auto-instrumentations/{chunk-6E22MYSW.mjs → chunk-26PKVUKB.mjs} +109 -5
  19. package/dist/auto-instrumentations/{chunk-AKKPLXTP.mjs → chunk-2AMDGD65.mjs} +160 -57
  20. package/dist/auto-instrumentations/{chunk-V5LEODRX.mjs → chunk-HD35AM3M.mjs} +1 -1
  21. package/dist/auto-instrumentations/{chunk-XYN63IG5.mjs → chunk-I55G56ZL.mjs} +21 -58
  22. package/dist/auto-instrumentations/{chunk-NRE4QUQR.mjs → chunk-JPUFNW7X.mjs} +140 -0
  23. package/dist/auto-instrumentations/{chunk-XZHHE4Y3.mjs → chunk-NP7V4XB2.mjs} +157 -3
  24. package/dist/auto-instrumentations/hook.mjs +396 -32
  25. package/dist/auto-instrumentations/index.cjs +298 -2
  26. package/dist/auto-instrumentations/index.d.mts +5 -1
  27. package/dist/auto-instrumentations/index.d.ts +5 -1
  28. package/dist/auto-instrumentations/index.mjs +6 -2
  29. package/dist/auto-instrumentations/loader/cjs-patch.cjs +105 -57
  30. package/dist/auto-instrumentations/loader/cjs-patch.mjs +2 -2
  31. package/dist/auto-instrumentations/loader/esm-hook.mjs +1 -1
  32. package/dist/browser.d.mts +683 -56
  33. package/dist/browser.d.ts +683 -56
  34. package/dist/browser.js +4242 -655
  35. package/dist/browser.mjs +4242 -655
  36. package/dist/{chunk-VYNNEKSA.js → chunk-BBE7SNRV.js} +248 -10
  37. package/dist/{chunk-VRZZQPAA.js → chunk-OBBWQW6K.js} +3351 -1392
  38. package/dist/{chunk-XIZOM2HO.mjs → chunk-UPFNQCGB.mjs} +2419 -460
  39. package/dist/{chunk-PN7EWK66.mjs → chunk-ZHUHZWFY.mjs} +241 -3
  40. package/dist/cli.js +2867 -668
  41. package/dist/edge-light.d.mts +1 -1
  42. package/dist/edge-light.d.ts +1 -1
  43. package/dist/edge-light.js +4242 -655
  44. package/dist/edge-light.mjs +4242 -655
  45. package/dist/index.d.mts +1267 -640
  46. package/dist/index.d.ts +1267 -640
  47. package/dist/index.js +2107 -630
  48. package/dist/index.mjs +1649 -172
  49. package/dist/instrumentation/index.d.mts +198 -6
  50. package/dist/instrumentation/index.d.ts +198 -6
  51. package/dist/instrumentation/index.js +2661 -581
  52. package/dist/instrumentation/index.mjs +2661 -581
  53. package/dist/vitest-evals-reporter.js +45 -43
  54. package/dist/vitest-evals-reporter.mjs +5 -3
  55. package/dist/workerd.d.mts +1 -1
  56. package/dist/workerd.d.ts +1 -1
  57. package/dist/workerd.js +4242 -655
  58. package/dist/workerd.mjs +4242 -655
  59. package/package.json +2 -3
  60. package/util/dist/index.d.mts +1545 -100
  61. package/util/dist/index.d.ts +1545 -100
@@ -7,6 +7,7 @@ import {
7
7
  claudeAgentSDKChannels,
8
8
  cloudflareAIChatChannels,
9
9
  cloudflareAgentsChannels,
10
+ cloudflareThinkChannels,
10
11
  cohereChannels,
11
12
  cursorSDKChannels,
12
13
  detectSpanOriginEnvironment,
@@ -31,6 +32,7 @@ import {
31
32
  langSmithChannels,
32
33
  mergeSpanOriginContext,
33
34
  mistralChannels,
35
+ ollamaChannels,
34
36
  openAIAgentsCoreChannels,
35
37
  openAIChannels,
36
38
  openAICodexChannels,
@@ -43,8 +45,9 @@ import {
43
45
  smithyClientChannels,
44
46
  smithyCoreChannels,
45
47
  strandsAgentSDKChannels,
48
+ voyageAIChannels,
46
49
  withSpanInstrumentationName
47
- } from "./chunk-PN7EWK66.mjs";
50
+ } from "./chunk-ZHUHZWFY.mjs";
48
51
 
49
52
  // src/id-gen.ts
50
53
  import { v4 as uuidv4 } from "uuid";
@@ -1119,15 +1122,15 @@ function mergeDictsWithPaths({
1119
1122
  function mergeDictsWithPathsHelper({
1120
1123
  mergeInto,
1121
1124
  mergeFrom,
1122
- path: path2,
1125
+ path: path3,
1123
1126
  mergePaths
1124
1127
  }) {
1125
1128
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
1126
1129
  if (FORBIDDEN_MERGE_KEYS.has(k)) return;
1127
- const fullPath = path2.concat([k]);
1130
+ const fullPath = path3.concat([k]);
1128
1131
  const fullPathSerialized = JSON.stringify(fullPath);
1129
1132
  const mergeIntoV = recordFind(mergeInto, k);
1130
- const isSetUnionField = path2.length === 0 && SET_UNION_FIELDS.has(k) && !mergePaths.has(fullPathSerialized);
1133
+ const isSetUnionField = path3.length === 0 && SET_UNION_FIELDS.has(k) && !mergePaths.has(fullPathSerialized);
1131
1134
  if (isSetUnionField && isArray(mergeIntoV) && isArray(mergeFromV)) {
1132
1135
  const seen = /* @__PURE__ */ new Set();
1133
1136
  const combined = [];
@@ -1160,9 +1163,9 @@ function mergeDicts(mergeInto, mergeFrom) {
1160
1163
  function recordFind(m, k) {
1161
1164
  return m[k];
1162
1165
  }
1163
- function getObjValueByPath(row, path2) {
1166
+ function getObjValueByPath(row, path3) {
1164
1167
  let curr = row;
1165
- for (const p of path2) {
1168
+ for (const p of path3) {
1166
1169
  if (!isObjectOrArray(curr)) {
1167
1170
  return null;
1168
1171
  }
@@ -1778,7 +1781,8 @@ var AclObjectType = z6.union([
1778
1781
  "org_member",
1779
1782
  "project_log",
1780
1783
  "org_project",
1781
- "org_audit_logs"
1784
+ "org_audit_logs",
1785
+ "project_group"
1782
1786
  ]),
1783
1787
  z6.null()
1784
1788
  ]);
@@ -1907,7 +1911,8 @@ var AsyncScoringState = z6.union([
1907
1911
  token: z6.string(),
1908
1912
  function_ids: z6.array(z6.unknown()),
1909
1913
  skip_logging: z6.union([z6.boolean(), z6.null()]).optional(),
1910
- triggered_functions: z6.union([z6.record(TriggeredFunctionState), z6.null()]).optional()
1914
+ triggered_functions: z6.union([z6.record(TriggeredFunctionState), z6.null()]).optional(),
1915
+ last_triggered_xact_id: z6.union([z6.string(), z6.number(), z6.null()]).optional()
1911
1916
  }),
1912
1917
  z6.object({ status: z6.literal("disabled") }),
1913
1918
  z6.null(),
@@ -1976,7 +1981,7 @@ var FunctionTypeEnum = z6.enum([
1976
1981
  "parameters",
1977
1982
  "sandbox"
1978
1983
  ]);
1979
- var NullableSavedFunctionId = z6.union([
1984
+ var FacetPreprocessorId = z6.union([
1980
1985
  z6.object({
1981
1986
  type: z6.literal("function"),
1982
1987
  id: z6.string(),
@@ -1987,10 +1992,23 @@ var NullableSavedFunctionId = z6.union([
1987
1992
  name: z6.string(),
1988
1993
  function_type: FunctionTypeEnum.optional().default("scorer")
1989
1994
  }),
1995
+ z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
1990
1996
  z6.null()
1991
1997
  ]);
1998
+ var SavedFunctionId = z6.union([
1999
+ z6.object({
2000
+ type: z6.literal("function"),
2001
+ id: z6.string(),
2002
+ version: z6.string().optional()
2003
+ }),
2004
+ z6.object({
2005
+ type: z6.literal("global"),
2006
+ name: z6.string(),
2007
+ function_type: FunctionTypeEnum.optional().default("scorer")
2008
+ })
2009
+ ]);
1992
2010
  var TopicMapGenerationSettings = z6.object({
1993
- algorithm: z6.enum(["hdbscan", "kmeans"]),
2011
+ algorithm: z6.enum(["hdbscan", "kmeans", "community"]),
1994
2012
  dimension_reduction: z6.enum(["umap", "pca", "none"]),
1995
2013
  sample_size: z6.number().int().gt(0).optional(),
1996
2014
  n_clusters: z6.number().int().gt(0).optional(),
@@ -2002,6 +2020,7 @@ var TopicMapGenerationSettings = z6.object({
2002
2020
  var TopicMapData = z6.object({
2003
2021
  type: z6.literal("topic_map"),
2004
2022
  source_facet: z6.string(),
2023
+ source_facet_function: SavedFunctionId.and(z6.unknown()).optional(),
2005
2024
  embedding_model: z6.string(),
2006
2025
  bundle_key: z6.string().optional(),
2007
2026
  report_key: z6.string().optional(),
@@ -2015,7 +2034,7 @@ var TopicMapData = z6.object({
2015
2034
  });
2016
2035
  var BatchedFacetData = z6.object({
2017
2036
  type: z6.literal("batched_facet"),
2018
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
2037
+ preprocessor: FacetPreprocessorId.optional(),
2019
2038
  facets: z6.array(
2020
2039
  z6.object({
2021
2040
  name: z6.string(),
@@ -2276,18 +2295,6 @@ var ObjectReferenceNullish = z6.union([
2276
2295
  }),
2277
2296
  z6.null()
2278
2297
  ]);
2279
- var SavedFunctionId = z6.union([
2280
- z6.object({
2281
- type: z6.literal("function"),
2282
- id: z6.string(),
2283
- version: z6.string().optional()
2284
- }),
2285
- z6.object({
2286
- type: z6.literal("global"),
2287
- name: z6.string(),
2288
- function_type: FunctionTypeEnum.optional().default("scorer")
2289
- })
2290
- ]);
2291
2298
  var DatasetEvent = z6.object({
2292
2299
  id: z6.string(),
2293
2300
  _xact_id: z6.string(),
@@ -2509,7 +2516,7 @@ var ExtendedSavedFunctionId = z6.union([
2509
2516
  ]);
2510
2517
  var FacetData = z6.object({
2511
2518
  type: z6.literal("facet"),
2512
- preprocessor: NullableSavedFunctionId.and(z6.unknown()).optional(),
2519
+ preprocessor: FacetPreprocessorId.optional(),
2513
2520
  prompt: z6.string(),
2514
2521
  model: z6.string().optional(),
2515
2522
  embedding_model: z6.string().optional(),
@@ -3014,6 +3021,19 @@ var MessageRole = z6.enum([
3014
3021
  "model",
3015
3022
  "developer"
3016
3023
  ]);
3024
+ var NullableSavedFunctionId = z6.union([
3025
+ z6.object({
3026
+ type: z6.literal("function"),
3027
+ id: z6.string(),
3028
+ version: z6.string().optional()
3029
+ }),
3030
+ z6.object({
3031
+ type: z6.literal("global"),
3032
+ name: z6.string(),
3033
+ function_type: FunctionTypeEnum.optional().default("scorer")
3034
+ }),
3035
+ z6.null()
3036
+ ]);
3017
3037
  var ObjectReference = z6.object({
3018
3038
  object_type: z6.enum([
3019
3039
  "project_logs",
@@ -3035,6 +3055,7 @@ var TraceScope = z6.object({
3035
3055
  });
3036
3056
  var OnlineScoreConfig = z6.union([
3037
3057
  z6.object({
3058
+ status: AutomationStatus.optional(),
3038
3059
  sampling_rate: z6.number().gte(0).lte(1),
3039
3060
  scorers: z6.array(SavedFunctionId),
3040
3061
  btql_filter: z6.union([z6.string(), z6.null()]).optional(),
@@ -3115,6 +3136,72 @@ var Project = z6.object({
3115
3136
  user_id: z6.union([z6.string(), z6.null()]).optional(),
3116
3137
  settings: ProjectSettings.optional()
3117
3138
  });
3139
+ var WindowedAutomationConfig = z6.object({
3140
+ event_type: z6.literal("windowed"),
3141
+ product_origin: z6.union([z6.literal("patterns"), z6.null()]).optional(),
3142
+ status: AutomationStatus.optional(),
3143
+ threshold: z6.object({
3144
+ calculation: z6.object({
3145
+ type: z6.literal("btql"),
3146
+ btql_query: z6.string().min(1),
3147
+ output: z6.object({
3148
+ type: z6.literal("scalar"),
3149
+ value_column: z6.string().min(1)
3150
+ })
3151
+ }),
3152
+ policy: z6.object({
3153
+ condition: z6.object({
3154
+ type: z6.literal("threshold"),
3155
+ operator: z6.enum(["lt", "lte", "gt", "gte", "eq", "neq"]),
3156
+ threshold: z6.number()
3157
+ }),
3158
+ pending_seconds: z6.number().int().gte(0).lte(2592e3),
3159
+ no_data_behavior: z6.enum(["keep_last", "resolve", "alert"]),
3160
+ renotify_interval_seconds: z6.union([z6.number(), z6.null()]).optional(),
3161
+ notify_on_recovery: z6.boolean().optional().default(true)
3162
+ })
3163
+ }).optional(),
3164
+ window: z6.object({
3165
+ window_seconds: z6.number().int().gte(1).lte(2592e3),
3166
+ schedule: z6.union([
3167
+ z6.object({
3168
+ type: z6.literal("interval"),
3169
+ evaluation_interval_seconds: z6.number().int().gte(1).lte(2592e3)
3170
+ }),
3171
+ z6.object({
3172
+ type: z6.literal("cron"),
3173
+ cron_expression: z6.string().min(1),
3174
+ timezone: z6.union([z6.string(), z6.null()]).optional()
3175
+ })
3176
+ ]),
3177
+ evaluation_delay_seconds: z6.number().int().gte(0).lte(2592e3)
3178
+ }),
3179
+ loop: z6.object({
3180
+ prompt: z6.string().min(1).max(1e4),
3181
+ include_trigger_input: z6.boolean().optional().default(false),
3182
+ agent_slug: z6.string().min(1),
3183
+ auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
3184
+ harness: z6.enum(["native", "codex", "claude-code"]).optional(),
3185
+ model: z6.string().min(1).optional(),
3186
+ reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
3187
+ }).optional(),
3188
+ actions: z6.array(
3189
+ z6.union([
3190
+ z6.object({
3191
+ type: z6.literal("webhook"),
3192
+ url: z6.string(),
3193
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3194
+ }),
3195
+ z6.object({
3196
+ type: z6.literal("slack"),
3197
+ workspace_id: z6.string(),
3198
+ channel: z6.string(),
3199
+ message_template: z6.string().optional(),
3200
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3201
+ })
3202
+ ])
3203
+ ).max(20).optional().default([])
3204
+ });
3118
3205
  var TopicAutomationFacetModel = z6.union([
3119
3206
  z6.enum(["brain-facet-latest", "brain-facet-1", "brain-facet-2"]),
3120
3207
  z6.null()
@@ -3156,7 +3243,8 @@ var TopicDigestAutomationConfig = z6.object({
3156
3243
  type: z6.literal("slack"),
3157
3244
  workspace_id: z6.string(),
3158
3245
  channel: z6.string(),
3159
- message_template: z6.string().optional()
3246
+ message_template: z6.string().optional(),
3247
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3160
3248
  }),
3161
3249
  topic_map_function_ids: z6.array(z6.string()).max(10).optional()
3162
3250
  });
@@ -3170,15 +3258,21 @@ var ProjectAutomation = z6.object({
3170
3258
  config: z6.union([
3171
3259
  z6.object({
3172
3260
  event_type: z6.literal("logs"),
3261
+ status: AutomationStatus.optional(),
3173
3262
  btql_filter: z6.string(),
3174
3263
  interval_seconds: z6.number().gte(1).lte(2592e3),
3175
3264
  action: z6.union([
3176
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
3265
+ z6.object({
3266
+ type: z6.literal("webhook"),
3267
+ url: z6.string(),
3268
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3269
+ }),
3177
3270
  z6.object({
3178
3271
  type: z6.literal("slack"),
3179
3272
  workspace_id: z6.string(),
3180
3273
  channel: z6.string(),
3181
- message_template: z6.string().optional()
3274
+ message_template: z6.string().optional(),
3275
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3182
3276
  })
3183
3277
  ])
3184
3278
  }),
@@ -3229,21 +3323,38 @@ var ProjectAutomation = z6.object({
3229
3323
  }),
3230
3324
  z6.object({
3231
3325
  event_type: z6.literal("environment_update"),
3326
+ status: AutomationStatus.optional(),
3232
3327
  environment_filter: z6.array(z6.string()).optional(),
3233
3328
  action: z6.union([
3234
- z6.object({ type: z6.literal("webhook"), url: z6.string() }),
3329
+ z6.object({
3330
+ type: z6.literal("webhook"),
3331
+ url: z6.string(),
3332
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3333
+ }),
3235
3334
  z6.object({
3236
3335
  type: z6.literal("slack"),
3237
3336
  workspace_id: z6.string(),
3238
3337
  channel: z6.string(),
3239
- message_template: z6.string().optional()
3338
+ message_template: z6.string().optional(),
3339
+ formatting_prompt: z6.string().min(1).max(1e4).optional()
3240
3340
  })
3241
3341
  ])
3242
3342
  }),
3343
+ WindowedAutomationConfig,
3243
3344
  TopicAutomationConfig,
3244
3345
  TopicDigestAutomationConfig
3245
3346
  ])
3246
3347
  });
3348
+ var ProjectGroup = z6.object({
3349
+ id: z6.string().uuid(),
3350
+ org_id: z6.string().uuid(),
3351
+ user_id: z6.union([z6.string(), z6.null()]).optional(),
3352
+ created: z6.union([z6.string(), z6.null()]).optional(),
3353
+ name: z6.string(),
3354
+ description: z6.union([z6.string(), z6.null()]).optional(),
3355
+ deleted_at: z6.union([z6.string(), z6.null()]).optional(),
3356
+ member_projects: z6.array(z6.string().uuid()).max(1e4)
3357
+ });
3247
3358
  var ProjectLogsEvent = z6.object({
3248
3359
  id: z6.string(),
3249
3360
  _xact_id: z6.string(),
@@ -3461,7 +3572,8 @@ var RunEval = z6.object({
3461
3572
  dataset_environment: z6.union([z6.string(), z6.null()]).optional(),
3462
3573
  _internal_btql: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional()
3463
3574
  }),
3464
- z6.object({ data: z6.array(z6.unknown()) })
3575
+ z6.object({ data: z6.array(z6.unknown()) }),
3576
+ z6.object({ experiment_name: z6.string() })
3465
3577
  ]),
3466
3578
  name: z6.string().optional(),
3467
3579
  parameters: z6.object({}).partial().passthrough().optional(),
@@ -3666,7 +3778,9 @@ var View = z6.object({
3666
3778
  "for_review_datasets"
3667
3779
  ]),
3668
3780
  name: z6.string(),
3781
+ description: z6.union([z6.string(), z6.null()]).optional(),
3669
3782
  created: z6.union([z6.string(), z6.null()]).optional(),
3783
+ updated_at: z6.union([z6.string(), z6.null()]).optional(),
3670
3784
  view_data: ViewData.optional(),
3671
3785
  options: ViewOptions.optional(),
3672
3786
  user_id: z6.union([z6.string(), z6.null()]).optional(),
@@ -4250,10 +4364,10 @@ var DiskCache = class {
4250
4364
  return;
4251
4365
  }
4252
4366
  const stats = await Promise.all(
4253
- paths.map(async (path2) => {
4254
- const stat2 = await isomorph_default.stat(path2);
4367
+ paths.map(async (path3) => {
4368
+ const stat2 = await isomorph_default.stat(path3);
4255
4369
  return {
4256
- path: path2,
4370
+ path: path3,
4257
4371
  mtime: stat2.mtime.getTime()
4258
4372
  };
4259
4373
  })
@@ -4908,6 +5022,9 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
4908
5022
  var INITIAL_SPAN_WRITE_AS_MERGE = /* @__PURE__ */ Symbol(
4909
5023
  "braintrust.initial-span-write-as-merge"
4910
5024
  );
5025
+ var RESUME_SPAN_WITHOUT_INITIAL_WRITE = /* @__PURE__ */ Symbol(
5026
+ "braintrust.resume-span-without-initial-write"
5027
+ );
4911
5028
  var INTERNAL_SPAN_CONTEXT = /* @__PURE__ */ Symbol("braintrust.internal-span-context");
4912
5029
  var BRAINTRUST_CURRENT_SPAN_STORE = /* @__PURE__ */ Symbol.for(
4913
5030
  "braintrust.currentSpanStore"
@@ -5505,9 +5622,9 @@ var HTTPConnection = class _HTTPConnection {
5505
5622
  this.headers["Authorization"] = `Bearer ${this.token}`;
5506
5623
  }
5507
5624
  }
5508
- async get(path2, params = void 0, config) {
5625
+ async get(path3, params = void 0, config) {
5509
5626
  const { headers, ...rest } = config || {};
5510
- const url = new URL(_urljoin(this.base_url, path2));
5627
+ const url = new URL(_urljoin(this.base_url, path3));
5511
5628
  url.search = new URLSearchParams(
5512
5629
  params ? Object.entries(params).filter(([_, v]) => v !== void 0).flatMap(
5513
5630
  ([k, v]) => v !== void 0 ? typeof v === "string" ? [[k, v]] : v.map((x) => [k, x]) : []
@@ -5528,7 +5645,7 @@ var HTTPConnection = class _HTTPConnection {
5528
5645
  })
5529
5646
  );
5530
5647
  }
5531
- async post(path2, params, config, retries = 0) {
5648
+ async post(path3, params, config, retries = 0) {
5532
5649
  const { headers, ...rest } = config || {};
5533
5650
  const this_fetch = this.fetch;
5534
5651
  const this_base_url = this.base_url;
@@ -5537,7 +5654,7 @@ var HTTPConnection = class _HTTPConnection {
5537
5654
  for (let i = 0; i < tries; i++) {
5538
5655
  try {
5539
5656
  return await checkResponse(
5540
- await this_fetch(_urljoin(this_base_url, path2), {
5657
+ await this_fetch(_urljoin(this_base_url, path3), {
5541
5658
  method: "POST",
5542
5659
  headers: {
5543
5660
  Accept: "application/json",
@@ -5558,7 +5675,7 @@ var HTTPConnection = class _HTTPConnection {
5558
5675
  throw error;
5559
5676
  }
5560
5677
  debugLogger.debug(
5561
- `Retrying API request ${path2} after ${formatHTTPError(error)}`
5678
+ `Retrying API request ${path3} after ${formatHTTPError(error)}`
5562
5679
  );
5563
5680
  const sleepTimeMs = HTTP_RETRY_BASE_SLEEP_TIME_S * 1e3 * 2 ** i + Math.random() * HTTP_RETRY_JITTER_MS;
5564
5681
  debugLogger.info(
@@ -6131,6 +6248,30 @@ function updateSpan({
6131
6248
  event
6132
6249
  });
6133
6250
  }
6251
+ function _internalResumeSpan({
6252
+ exported,
6253
+ state
6254
+ }) {
6255
+ const resolvedState = state ?? _globalState;
6256
+ const components = SpanComponentsV4.fromStr(exported);
6257
+ const { row_id, root_span_id, span_id } = components.data;
6258
+ if (!row_id || !root_span_id || !span_id) {
6259
+ throw new Error("Only exported root spans can be resumed");
6260
+ }
6261
+ return new SpanImpl({
6262
+ state: resolvedState,
6263
+ parentObjectType: components.data.object_type,
6264
+ parentObjectId: new LazyValue(
6265
+ spanComponentsToObjectIdLambda(resolvedState, components)
6266
+ ),
6267
+ parentComputeObjectMetadataArgs: void 0,
6268
+ parentSpanIds: { parentSpanIds: [], rootSpanId: root_span_id },
6269
+ spanId: span_id,
6270
+ event: { id: row_id },
6271
+ propagatedEvent: components.data.propagated_event ?? void 0,
6272
+ [RESUME_SPAN_WITHOUT_INITIAL_WRITE]: true
6273
+ });
6274
+ }
6134
6275
  function spanComponentsToObjectIdLambda(state, components) {
6135
6276
  if (components.data.object_id) {
6136
6277
  const ret = components.data.object_id;
@@ -9011,7 +9152,7 @@ var ObjectFetcher = class {
9011
9152
  const objectId = await this.id;
9012
9153
  const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
9013
9154
  const internalLimit = getInternalBtqlLimit(this._internal_btql);
9014
- const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
9155
+ let remainingLimit = internalLimit;
9015
9156
  const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
9016
9157
  Object.entries(this._internal_btql ?? {}).filter(
9017
9158
  ([key]) => key !== "cursor" && key !== "limit" && key !== "select" && key !== "from"
@@ -9020,6 +9161,10 @@ var ObjectFetcher = class {
9020
9161
  let cursor = void 0;
9021
9162
  let iterations = 0;
9022
9163
  while (true) {
9164
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
9165
+ return;
9166
+ }
9167
+ const limit = remainingLimit === void 0 ? batchLimit : Math.min(batchLimit, remainingLimit);
9023
9168
  const resp = await state.apiConn().post(
9024
9169
  `btql`,
9025
9170
  {
@@ -9059,7 +9204,14 @@ var ObjectFetcher = class {
9059
9204
  const respJson = await resp.json();
9060
9205
  const mutate = this.mutateRecord;
9061
9206
  for (const record of respJson.data ?? []) {
9062
- yield mutate ? mutate(record) : record;
9207
+ if (remainingLimit !== void 0 && remainingLimit <= 0) {
9208
+ return;
9209
+ }
9210
+ const mutatedRecord = mutate ? mutate(record) : record;
9211
+ if (remainingLimit !== void 0) {
9212
+ remainingLimit--;
9213
+ }
9214
+ yield mutatedRecord;
9063
9215
  }
9064
9216
  if (!respJson.cursor) {
9065
9217
  break;
@@ -9579,7 +9731,9 @@ var SpanImpl = class _SpanImpl {
9579
9731
  this._rootSpanId = resolvedIds.rootSpanId;
9580
9732
  this._spanParents = resolvedIds.spanParents;
9581
9733
  this.isMerge = args[INITIAL_SPAN_WRITE_AS_MERGE] === true;
9582
- this.logInternal({ event, internalData });
9734
+ if (!args[RESUME_SPAN_WITHOUT_INITIAL_WRITE]) {
9735
+ this.logInternal({ event, internalData });
9736
+ }
9583
9737
  this.isMerge = true;
9584
9738
  }
9585
9739
  getParentInfo() {
@@ -10883,6 +11037,25 @@ function getCachedMetricFromHeaders(headers) {
10883
11037
  return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
10884
11038
  }
10885
11039
 
11040
+ // src/wrappers/anthropic-session-collector.ts
11041
+ var sessionStreamCollectors = /* @__PURE__ */ new WeakMap();
11042
+ function registerAnthropicSessionStreamCollector(stream, collector) {
11043
+ sessionStreamCollectors.set(stream, collector);
11044
+ }
11045
+ function collectAnthropicSession(stream) {
11046
+ const collector = sessionStreamCollectors.get(stream);
11047
+ if (!collector) {
11048
+ return stream;
11049
+ }
11050
+ sessionStreamCollectors.delete(stream);
11051
+ try {
11052
+ collector();
11053
+ } catch (error) {
11054
+ debugLogger.error("Failed to collect Anthropic Sessions stream:", error);
11055
+ }
11056
+ return stream;
11057
+ }
11058
+
10886
11059
  // src/instrumentation/core/stream-patcher.ts
10887
11060
  function isAsyncIterable(value) {
10888
11061
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
@@ -10907,6 +11080,34 @@ function patchStreamIfNeeded(stream, options) {
10907
11080
  );
10908
11081
  return stream;
10909
11082
  }
11083
+ const chunks = [];
11084
+ let completed = false;
11085
+ const notifyCancellation = async () => {
11086
+ try {
11087
+ await (options.onCancel ?? options.onComplete)(chunks);
11088
+ } catch (error) {
11089
+ debugLogger.error("Error in stream cancellation handler:", error);
11090
+ }
11091
+ };
11092
+ const patchAbortIfPresent = () => {
11093
+ try {
11094
+ if ("abort" in stream && typeof stream.abort === "function") {
11095
+ const originalAbort = stream.abort.bind(stream);
11096
+ stream.abort = (...args) => {
11097
+ try {
11098
+ return originalAbort(...args);
11099
+ } finally {
11100
+ if (!completed) {
11101
+ completed = true;
11102
+ void notifyCancellation();
11103
+ }
11104
+ }
11105
+ };
11106
+ }
11107
+ } catch (error) {
11108
+ debugLogger.warn("Failed to patch stream abort method:", error);
11109
+ }
11110
+ };
10910
11111
  if (hasAsyncIteratorMethods(stream) && isSelfAsyncIterator(stream)) {
10911
11112
  if ("__braintrust_patched_iterator_methods" in stream) {
10912
11113
  return stream;
@@ -10915,8 +11116,6 @@ function patchStreamIfNeeded(stream, options) {
10915
11116
  const originalNext = stream.next.bind(stream);
10916
11117
  const originalReturn = typeof stream.return === "function" ? stream.return.bind(stream) : null;
10917
11118
  const originalThrow = typeof stream.throw === "function" ? stream.throw.bind(stream) : null;
10918
- const chunks = [];
10919
- let completed = false;
10920
11119
  stream.next = async (...args) => {
10921
11120
  try {
10922
11121
  const result = await runNextWithWrapper(
@@ -10968,11 +11167,7 @@ function patchStreamIfNeeded(stream, options) {
10968
11167
  stream.return = async (...args) => {
10969
11168
  if (!completed) {
10970
11169
  completed = true;
10971
- try {
10972
- await options.onComplete(chunks);
10973
- } catch (error) {
10974
- console.error("Error in stream onComplete handler:", error);
10975
- }
11170
+ await notifyCancellation();
10976
11171
  }
10977
11172
  return originalReturn(...args);
10978
11173
  };
@@ -10997,6 +11192,7 @@ function patchStreamIfNeeded(stream, options) {
10997
11192
  Object.defineProperty(stream, "__braintrust_patched_iterator_methods", {
10998
11193
  value: true
10999
11194
  });
11195
+ patchAbortIfPresent();
11000
11196
  return stream;
11001
11197
  } catch (error) {
11002
11198
  console.warn("Failed to patch stream iterator methods:", error);
@@ -11010,8 +11206,6 @@ function patchStreamIfNeeded(stream, options) {
11010
11206
  const patchedIteratorFn = function() {
11011
11207
  const iterator = originalIteratorFn.call(this);
11012
11208
  const originalNext = iterator.next.bind(iterator);
11013
- const chunks = [];
11014
- let completed = false;
11015
11209
  iterator.next = async function(...args) {
11016
11210
  try {
11017
11211
  const result = await runNextWithWrapper(
@@ -11064,11 +11258,7 @@ function patchStreamIfNeeded(stream, options) {
11064
11258
  iterator.return = async function(...args) {
11065
11259
  if (!completed) {
11066
11260
  completed = true;
11067
- try {
11068
- await options.onComplete(chunks);
11069
- } catch (error) {
11070
- console.error("Error in stream onComplete handler:", error);
11071
- }
11261
+ await notifyCancellation();
11072
11262
  }
11073
11263
  return originalReturn(...args);
11074
11264
  };
@@ -11097,6 +11287,7 @@ function patchStreamIfNeeded(stream, options) {
11097
11287
  value: true
11098
11288
  });
11099
11289
  stream[Symbol.asyncIterator] = patchedIteratorFn;
11290
+ patchAbortIfPresent();
11100
11291
  return stream;
11101
11292
  } catch (error) {
11102
11293
  console.warn("Failed to patch stream:", error);
@@ -11845,6 +12036,33 @@ function traceStreamingChannel(channel, config) {
11845
12036
  const { span, startTime } = spanData;
11846
12037
  if (isAsyncIterable(asyncEndEvent.result)) {
11847
12038
  let firstChunkTime;
12039
+ const handleStreamError = (error) => {
12040
+ try {
12041
+ span.log({ error });
12042
+ } catch (loggingError) {
12043
+ debugLogger.error(
12044
+ `Error logging failure for ${channelName}:`,
12045
+ loggingError
12046
+ );
12047
+ }
12048
+ try {
12049
+ span.end();
12050
+ } catch (endingError) {
12051
+ debugLogger.error(
12052
+ `Error ending span for ${channelName}:`,
12053
+ endingError
12054
+ );
12055
+ }
12056
+ states.delete(event);
12057
+ runStreamingErrorHook({
12058
+ channelName,
12059
+ config,
12060
+ error,
12061
+ event: asyncEndEvent,
12062
+ span,
12063
+ startTime
12064
+ });
12065
+ };
11848
12066
  patchStreamIfNeeded(asyncEndEvent.result, {
11849
12067
  onChunk: () => {
11850
12068
  if (firstChunkTime === void 0) {
@@ -11924,33 +12142,12 @@ function traceStreamingChannel(channel, config) {
11924
12142
  });
11925
12143
  }
11926
12144
  },
11927
- onError: (error) => {
11928
- try {
11929
- span.log({ error });
11930
- } catch (loggingError) {
11931
- debugLogger.error(
11932
- `Error logging failure for ${channelName}:`,
11933
- loggingError
11934
- );
11935
- }
11936
- try {
11937
- span.end();
11938
- } catch (endingError) {
11939
- debugLogger.error(
11940
- `Error ending span for ${channelName}:`,
11941
- endingError
11942
- );
11943
- }
11944
- states.delete(event);
11945
- runStreamingErrorHook({
11946
- channelName,
11947
- config,
11948
- error,
11949
- event: asyncEndEvent,
11950
- span,
11951
- startTime
11952
- });
11953
- }
12145
+ onCancel: () => {
12146
+ const error = new Error("Stream cancelled before completion");
12147
+ error.name = "AbortError";
12148
+ handleStreamError(error);
12149
+ },
12150
+ onError: handleStreamError
11954
12151
  });
11955
12152
  return;
11956
12153
  }
@@ -12266,6 +12463,22 @@ function processInputAttachments(input) {
12266
12463
  };
12267
12464
  }
12268
12465
  }
12466
+ 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;
12467
+ const voyageBase64Value = voyageBase64Key ? node[voyageBase64Key] : void 0;
12468
+ if (voyageBase64Key && typeof voyageBase64Value === "string" && voyageBase64Value.startsWith("data:")) {
12469
+ const mediaType = inferMediaTypeFromDataUrl(
12470
+ voyageBase64Value,
12471
+ node.type === "video_base64" ? "video/mp4" : "image/png"
12472
+ );
12473
+ const filename = `${node.type === "video_base64" ? "video" : "image"}.${getExtensionFromMediaType(mediaType)}`;
12474
+ const attachment = toAttachment(voyageBase64Value, mediaType, filename);
12475
+ if (attachment) {
12476
+ return {
12477
+ ...node,
12478
+ [voyageBase64Key]: attachment
12479
+ };
12480
+ }
12481
+ }
12269
12482
  if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
12270
12483
  const mediaType = inferMediaTypeFromDataUrl(
12271
12484
  node.file.file_data,
@@ -12710,6 +12923,29 @@ function currentWorkflowAgentWrapperSpan() {
12710
12923
  return void 0;
12711
12924
  }
12712
12925
 
12926
+ // src/instrumentation/plugins/cloudflare-think-context.ts
12927
+ var cloudflareThinkSpans = /* @__PURE__ */ new Map();
12928
+ function registerCloudflareThinkSpan(span) {
12929
+ if (span.spanId) {
12930
+ cloudflareThinkSpans.set(span.spanId, span);
12931
+ }
12932
+ }
12933
+ function unregisterCloudflareThinkSpan(span) {
12934
+ if (span.spanId) {
12935
+ cloudflareThinkSpans.delete(span.spanId);
12936
+ }
12937
+ }
12938
+ function currentCloudflareThinkSpan() {
12939
+ const parentSpanIds = _internalGetGlobalState()?.contextManager.getParentSpanIds()?.spanParents ?? [];
12940
+ for (const parentSpanId of parentSpanIds) {
12941
+ const span = cloudflareThinkSpans.get(parentSpanId);
12942
+ if (span) {
12943
+ return span;
12944
+ }
12945
+ }
12946
+ return void 0;
12947
+ }
12948
+
12713
12949
  // src/vendor-sdk-types/ai-sdk-v7-telemetry.ts
12714
12950
  var BRAINTRUST_AI_SDK_V7_OPERATION_KEY = /* @__PURE__ */ Symbol.for(
12715
12951
  "braintrust.ai-sdk.v7.telemetry-operation-key"
@@ -12821,6 +13057,7 @@ var AISDKPlugin = class extends BasePlugin {
12821
13057
  traceStreamingChannel(aiSDKChannels.streamText, {
12822
13058
  name: "streamText",
12823
13059
  type: "function" /* FUNCTION */,
13060
+ shouldTrace: () => currentCloudflareThinkSpan() === void 0,
12824
13061
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
12825
13062
  extractOutput: (result, endEvent) => processAISDKOutput(
12826
13063
  result,
@@ -12841,6 +13078,7 @@ var AISDKPlugin = class extends BasePlugin {
12841
13078
  traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
12842
13079
  name: "streamText",
12843
13080
  type: "function" /* FUNCTION */,
13081
+ shouldTrace: () => currentCloudflareThinkSpan() === void 0,
12844
13082
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
12845
13083
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
12846
13084
  defaultDenyOutputPaths: denyOutputPaths,
@@ -13423,7 +13661,7 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13423
13661
  return defaultDenyOutputPaths;
13424
13662
  }
13425
13663
  const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
13426
- if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path2) => typeof path2 === "string")) {
13664
+ if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path3) => typeof path3 === "string")) {
13427
13665
  return runtimeDenyOutputPaths;
13428
13666
  }
13429
13667
  return defaultDenyOutputPaths;
@@ -13826,6 +14064,23 @@ function prepareAISDKWorkflowAgentStreamInput(params, event, span, defaultDenyOu
13826
14064
  metadata
13827
14065
  };
13828
14066
  }
14067
+ function prepareAISDKAgentCallInput(params, event, span, defaultDenyOutputPaths = DEFAULT_DENY_OUTPUT_PATHS) {
14068
+ const { input } = processAISDKWorkflowAgentCallInput(params);
14069
+ const metadata = extractMetadataFromCallParams(params, event.self);
14070
+ const childTracing = prepareAISDKChildTracing(
14071
+ params,
14072
+ event.self,
14073
+ span,
14074
+ defaultDenyOutputPaths,
14075
+ event.aiSDK,
14076
+ { agentOwner: true }
14077
+ );
14078
+ event.modelWrapped = childTracing.modelWrapped;
14079
+ if (childTracing.cleanup) {
14080
+ event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
14081
+ }
14082
+ return { input, metadata };
14083
+ }
13829
14084
  function prepareAISDKEmbedInput(params, self) {
13830
14085
  return {
13831
14086
  input: { ...params },
@@ -13849,6 +14104,18 @@ function extractTopLevelAISDKMetrics(result, event, startTime) {
13849
14104
  }
13850
14105
  return metrics;
13851
14106
  }
14107
+ async function extractResolvedAISDKTokenMetrics(result) {
14108
+ for (const field of ["totalUsage", "usage"]) {
14109
+ try {
14110
+ const usage = await Promise.resolve(result[field]);
14111
+ if (usage !== void 0) {
14112
+ return extractTokenMetrics({ [field]: usage });
14113
+ }
14114
+ } catch {
14115
+ }
14116
+ }
14117
+ return extractTokenMetrics(result);
14118
+ }
13852
14119
  function hasModelChildTracing(event) {
13853
14120
  return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
13854
14121
  }
@@ -14666,13 +14933,15 @@ function patchAISDKStreamingResult(args) {
14666
14933
  const {
14667
14934
  defaultDenyOutputPaths,
14668
14935
  endEvent,
14936
+ forceTopLevelMetrics,
14669
14937
  onComplete,
14670
14938
  onCancel,
14671
14939
  onError,
14672
14940
  result,
14673
14941
  resolvePromiseUsage,
14674
14942
  span,
14675
- startTime
14943
+ startTime,
14944
+ transformOutput
14676
14945
  } = args;
14677
14946
  if (!result || typeof result !== "object") {
14678
14947
  return false;
@@ -14725,8 +14994,8 @@ function patchAISDKStreamingResult(args) {
14725
14994
  }
14726
14995
  outputLogged = true;
14727
14996
  try {
14728
- const metrics = extractTopLevelAISDKMetrics(result, endEvent);
14729
- if (resolvePromiseUsage) {
14997
+ const metrics = forceTopLevelMetrics ? await extractResolvedAISDKTokenMetrics(result) : extractTopLevelAISDKMetrics(result, endEvent);
14998
+ if (resolvePromiseUsage && !forceTopLevelMetrics) {
14730
14999
  try {
14731
15000
  const resultRecord2 = result;
14732
15001
  const pendingUsage = resultRecord2.totalUsage ?? resultRecord2.usage;
@@ -14745,10 +15014,11 @@ function patchAISDKStreamingResult(args) {
14745
15014
  if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
14746
15015
  metrics.time_to_first_token = firstChunkTime - startTime;
14747
15016
  }
14748
- const output = await processAISDKStreamingOutput(
15017
+ const processedOutput = await processAISDKStreamingOutput(
14749
15018
  result,
14750
15019
  resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
14751
15020
  );
15021
+ const output = transformOutput ? transformOutput(processedOutput) : processedOutput;
14752
15022
  const metadata = buildResolvedMetadataPayload(result).metadata;
14753
15023
  try {
14754
15024
  span.log({
@@ -15153,11 +15423,11 @@ function processAISDKOutput(output, denyOutputPaths) {
15153
15423
  if (!output) return output;
15154
15424
  const merged = extractSerializableOutputFields(output);
15155
15425
  const deleteOutputPaths = denyOutputPaths.filter(
15156
- (path2) => path2.toLowerCase().endsWith("headers")
15426
+ (path3) => path3.toLowerCase().endsWith("headers")
15157
15427
  );
15158
15428
  const sanitized = omit(merged, denyOutputPaths, deleteOutputPaths);
15159
- for (const path2 of TRANSPORT_PAYLOAD_ROOT_PATHS) {
15160
- const stack = [{ obj: sanitized, keys: parsePath(path2) }];
15429
+ for (const path3 of TRANSPORT_PAYLOAD_ROOT_PATHS) {
15430
+ const stack = [{ obj: sanitized, keys: parsePath(path3) }];
15161
15431
  while (stack.length > 0) {
15162
15432
  const entry = stack.pop();
15163
15433
  if (!entry || entry.keys.length === 0) {
@@ -15596,11 +15866,11 @@ function firstNumber(...values) {
15596
15866
  function deepCopy(obj) {
15597
15867
  return JSON.parse(JSON.stringify(obj));
15598
15868
  }
15599
- function parsePath(path2) {
15869
+ function parsePath(path3) {
15600
15870
  const keys = [];
15601
15871
  let current = "";
15602
- for (let i = 0; i < path2.length; i++) {
15603
- const char = path2[i];
15872
+ for (let i = 0; i < path3.length; i++) {
15873
+ const char = path3[i];
15604
15874
  if (char === ".") {
15605
15875
  if (current) {
15606
15876
  keys.push(current);
@@ -15613,8 +15883,8 @@ function parsePath(path2) {
15613
15883
  }
15614
15884
  let bracketContent = "";
15615
15885
  i++;
15616
- while (i < path2.length && path2[i] !== "]") {
15617
- bracketContent += path2[i];
15886
+ while (i < path3.length && path3[i] !== "]") {
15887
+ bracketContent += path3[i];
15618
15888
  i++;
15619
15889
  }
15620
15890
  if (bracketContent === "") {
@@ -15669,9 +15939,9 @@ function omitAtPath(obj, keys, deleteLeaf = false) {
15669
15939
  function omit(obj, paths, deletePaths = []) {
15670
15940
  const result = deepCopy(obj);
15671
15941
  const deletePathSet = new Set(deletePaths);
15672
- for (const path2 of paths) {
15673
- const keys = parsePath(path2);
15674
- omitAtPath(result, keys, deletePathSet.has(path2));
15942
+ for (const path3 of paths) {
15943
+ const keys = parsePath(path3);
15944
+ omitAtPath(result, keys, deletePathSet.has(path3));
15675
15945
  }
15676
15946
  return result;
15677
15947
  }
@@ -16897,17 +17167,20 @@ var FlueObserveBridge = class {
16897
17167
  return;
16898
17168
  }
16899
17169
  const metadata = {
17170
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
16900
17171
  ...extractEventMetadata(event),
16901
17172
  "flue.operation": event.operationKind,
16902
17173
  provider: "flue"
16903
17174
  };
16904
17175
  const parent = this.parentSpanForEvent(event);
16905
- const span = startFlueSpan(parent, {
17176
+ const args = {
16906
17177
  name: `flue.${event.operationKind}`,
16907
17178
  spanAttributes: { type: "task" /* TASK */ },
16908
17179
  startTime: eventTime(event.timestamp),
16909
17180
  event: { metadata }
16910
- });
17181
+ };
17182
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
17183
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
16911
17184
  this.operationsById.set(event.operationId, { metadata, span });
16912
17185
  }
16913
17186
  handleOperation(event) {
@@ -16915,16 +17188,21 @@ var FlueObserveBridge = class {
16915
17188
  return;
16916
17189
  }
16917
17190
  const state = this.operationsById.get(event.operationId) ?? this.startSyntheticOperation(event);
16918
- const output = operationOutput(event);
17191
+ const output = operationOutput(event) ?? outputFromAgentTurn(state.latestAgentOutput);
16919
17192
  const metadata = {
16920
17193
  ...state.metadata,
16921
17194
  ...extractEventMetadata(event),
16922
17195
  ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
16923
17196
  ...event.usage ? { "flue.usage": event.usage } : {}
16924
17197
  };
17198
+ const input = flueOperationInput(event);
17199
+ if (!state.loggedInput && input !== void 0) {
17200
+ safeLog(state.span, { input });
17201
+ state.loggedInput = true;
17202
+ }
16925
17203
  this.finishPendingChildrenForOperation(event, output);
16926
17204
  safeLog(state.span, {
16927
- ...event.isError ? { error: toLoggedError(event.error) } : {},
17205
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
16928
17206
  metadata,
16929
17207
  metrics: durationMetrics(event.durationMs),
16930
17208
  output
@@ -16938,6 +17216,8 @@ var FlueObserveBridge = class {
16938
17216
  return;
16939
17217
  }
16940
17218
  const input = flueTurnRequestInput(event);
17219
+ const operation = event.operationId ? this.operationsById.get(event.operationId) : void 0;
17220
+ const turnInput = prepareFlueTurnInput(event, input, operation);
16941
17221
  const model = flueTurnRequestModel(event);
16942
17222
  const provider = flueTurnRequestProvider(event);
16943
17223
  const api = flueTurnRequestApi(event);
@@ -16950,20 +17230,22 @@ var FlueObserveBridge = class {
16950
17230
  ...provider ? { "flue.provider": provider } : {},
16951
17231
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {},
16952
17232
  ...reasoning ? { reasoning } : {},
16953
- ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
16954
- ...input?.tools ? { tools: input.tools } : {}
17233
+ ...turnInput.metadata
16955
17234
  };
16956
17235
  const parent = this.parentSpanForTurn(event);
16957
17236
  const span = startFlueSpan(parent, {
16958
- name: `llm:${model ?? event.purpose ?? "unknown"}`,
17237
+ name: "flue.turn",
16959
17238
  spanAttributes: { type: "llm" /* LLM */ },
16960
17239
  startTime: eventTime(event.timestamp),
16961
17240
  event: {
16962
- input: input?.messages,
17241
+ input: turnInput.messages,
16963
17242
  metadata
16964
17243
  }
16965
17244
  });
16966
- this.logOperationInput(event.operationId, input?.messages ?? input);
17245
+ this.logOperationInput(
17246
+ event.operationId,
17247
+ latestUserMessageInput(input?.messages)
17248
+ );
16967
17249
  this.turnsByKey.set(key, { metadata, span });
16968
17250
  }
16969
17251
  handleTurn(event) {
@@ -16999,6 +17281,12 @@ var FlueObserveBridge = class {
16999
17281
  },
17000
17282
  output
17001
17283
  });
17284
+ if (event.purpose === "agent" && event.operationId) {
17285
+ const operation = this.operationsById.get(event.operationId);
17286
+ if (operation) {
17287
+ operation.latestAgentOutput = output;
17288
+ }
17289
+ }
17002
17290
  safeEnd(state.span, eventTime(event.timestamp));
17003
17291
  this.turnsByKey.delete(key);
17004
17292
  }
@@ -17078,7 +17366,7 @@ var FlueObserveBridge = class {
17078
17366
  return;
17079
17367
  }
17080
17368
  safeLog(state.span, {
17081
- ...event.isError ? { error: toLoggedError(event.result) } : {},
17369
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.result) } : {},
17082
17370
  metadata: {
17083
17371
  ...state.metadata,
17084
17372
  ...extractEventMetadata(event),
@@ -17124,6 +17412,7 @@ var FlueObserveBridge = class {
17124
17412
  ...event.usage ? { "flue.usage": event.usage } : {}
17125
17413
  };
17126
17414
  safeLog(state.span, {
17415
+ ...event.isError ? { error: toLoggedError(event.errorInfo ?? event.error) } : {},
17127
17416
  metadata,
17128
17417
  metrics: {
17129
17418
  ...durationMetrics(event.durationMs),
@@ -17203,16 +17492,20 @@ var FlueObserveBridge = class {
17203
17492
  }
17204
17493
  startSyntheticOperation(event) {
17205
17494
  const metadata = {
17495
+ ...event.runId ? this.runsById.get(event.runId)?.metadata : {},
17206
17496
  ...extractEventMetadata(event),
17207
17497
  "flue.operation": event.operationKind,
17208
17498
  provider: "flue"
17209
17499
  };
17210
- const span = startFlueSpan(this.parentSpanForEvent(event), {
17500
+ const args = {
17211
17501
  name: `flue.${event.operationKind}`,
17212
17502
  spanAttributes: { type: "task" /* TASK */ },
17213
17503
  startTime: eventTime(event.timestamp),
17214
17504
  event: { metadata }
17215
- });
17505
+ };
17506
+ const parent = this.parentSpanForEvent(event);
17507
+ const runSpan = event.runId ? this.runsById.get(event.runId)?.span : void 0;
17508
+ const span = event.operationKind === "prompt" && (!parent || parent === runSpan) ? startFlueRootSpan(args) : startFlueSpan(parent, args);
17216
17509
  return { metadata, span };
17217
17510
  }
17218
17511
  startSyntheticTurn(event) {
@@ -17228,7 +17521,7 @@ var FlueObserveBridge = class {
17228
17521
  ...event.purpose ? { "flue.turn_purpose": event.purpose } : {}
17229
17522
  };
17230
17523
  const span = startFlueSpan(this.parentSpanForEvent(event), {
17231
- name: `llm:${model ?? event.purpose ?? "unknown"}`,
17524
+ name: "flue.turn",
17232
17525
  spanAttributes: { type: "llm" /* LLM */ },
17233
17526
  startTime: eventTime(event.timestamp),
17234
17527
  event: { metadata }
@@ -17360,7 +17653,10 @@ function extractEventMetadata(event, ctx) {
17360
17653
  return {
17361
17654
  ...event.runId ? { "flue.run_id": event.runId } : {},
17362
17655
  ...event.instanceId ? { "flue.instance_id": event.instanceId } : {},
17656
+ ...event.submissionId ? { "flue.submission_id": event.submissionId } : {},
17363
17657
  ...event.dispatchId ? { "flue.dispatch_id": event.dispatchId } : {},
17658
+ ...event.agentName ? { "flue.agent_name": event.agentName } : {},
17659
+ ...event.conversationId ? { "flue.conversation_id": event.conversationId } : {},
17364
17660
  ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
17365
17661
  ...event.session ? { "flue.session": event.session } : {},
17366
17662
  ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
@@ -17388,8 +17684,73 @@ function flueRunInput(event) {
17388
17684
  function flueTurnRequestInput(event) {
17389
17685
  return event.request?.input ?? event.input;
17390
17686
  }
17687
+ function prepareFlueTurnInput(event, input, operation) {
17688
+ const messages = input?.messages;
17689
+ const tracksUserTurn = event.purpose === "agent" && operation?.metadata["flue.operation"] === "prompt" && Array.isArray(messages);
17690
+ if (!tracksUserTurn) {
17691
+ return {
17692
+ messages,
17693
+ metadata: {
17694
+ ...input?.systemPrompt ? { "flue.system_prompt": input.systemPrompt } : {},
17695
+ ...input?.tools ? { tools: input.tools } : {}
17696
+ }
17697
+ };
17698
+ }
17699
+ const previous = operation.turnInputState;
17700
+ const previousMessageCount = previous?.messageCount ?? 0;
17701
+ const boundaryFingerprint = messages.length > 0 ? fingerprintJsonValue(messages[messages.length - 1]) : void 0;
17702
+ const continuesPreviousInput = previous !== void 0 && messages.length >= previousMessageCount && (previousMessageCount === 0 || previous.boundaryFingerprint !== void 0 && previous.boundaryFingerprint === fingerprintJsonValue(messages[previousMessageCount - 1]));
17703
+ const inputMode = previous === void 0 ? "full" : continuesPreviousInput ? "delta" : "reset";
17704
+ const systemPromptFingerprint = fingerprintJsonValue(input?.systemPrompt);
17705
+ const toolsFingerprint = fingerprintJsonValue(input?.tools);
17706
+ operation.turnInputState = {
17707
+ ...boundaryFingerprint !== void 0 ? { boundaryFingerprint } : {},
17708
+ messageCount: messages.length,
17709
+ ...systemPromptFingerprint !== void 0 ? { systemPromptFingerprint } : {},
17710
+ ...toolsFingerprint !== void 0 ? { toolsFingerprint } : {}
17711
+ };
17712
+ return {
17713
+ messages: continuesPreviousInput ? messages.slice(previousMessageCount) : messages,
17714
+ metadata: {
17715
+ "flue.input_mode": inputMode,
17716
+ ...continuesPreviousInput ? { "flue.input_message_offset": previousMessageCount } : {},
17717
+ ...input?.systemPrompt && (!continuesPreviousInput || systemPromptFingerprint !== previous?.systemPromptFingerprint) ? { "flue.system_prompt": input.systemPrompt } : {},
17718
+ ...input?.tools && (!continuesPreviousInput || toolsFingerprint !== previous?.toolsFingerprint) ? { tools: input.tools } : {}
17719
+ }
17720
+ };
17721
+ }
17722
+ function fingerprintJsonValue(value) {
17723
+ try {
17724
+ const serialized = JSON.stringify(value);
17725
+ if (serialized === void 0) {
17726
+ return void 0;
17727
+ }
17728
+ let hash = 2166136261;
17729
+ for (let i = 0; i < serialized.length; i++) {
17730
+ hash = Math.imul(hash ^ serialized.charCodeAt(i), 16777619);
17731
+ }
17732
+ return `${serialized.length}:${hash >>> 0}`;
17733
+ } catch {
17734
+ return void 0;
17735
+ }
17736
+ }
17737
+ function latestUserMessageInput(messages) {
17738
+ if (!messages) {
17739
+ return void 0;
17740
+ }
17741
+ for (let i = messages.length - 1; i >= 0; i--) {
17742
+ const message = messages[i];
17743
+ if (isObjectLike(message) && Reflect.get(message, "role") === "user") {
17744
+ return [message];
17745
+ }
17746
+ }
17747
+ return void 0;
17748
+ }
17749
+ function flueOperationInput(event) {
17750
+ return typeof event.agentInput?.text === "string" ? [{ content: event.agentInput.text, role: "user" }] : void 0;
17751
+ }
17391
17752
  function flueTurnRequestModel(event) {
17392
- return event.request?.model ?? event.model;
17753
+ return event.request?.requestedModel ?? event.request?.model ?? event.model;
17393
17754
  }
17394
17755
  function flueTurnRequestProvider(event) {
17395
17756
  return event.request?.providerName ?? event.provider ?? event.request?.providerId;
@@ -17398,10 +17759,10 @@ function flueTurnRequestApi(event) {
17398
17759
  return event.request?.api ?? event.api;
17399
17760
  }
17400
17761
  function flueTurnRequestReasoning(event) {
17401
- return event.request?.reasoning ?? event.reasoning;
17762
+ return event.request?.reasoningLevel ?? event.request?.reasoning ?? event.reasoning;
17402
17763
  }
17403
17764
  function flueTurnModel(event) {
17404
- return event.request?.model ?? event.model;
17765
+ return event.response?.responseModel ?? event.request?.requestedModel ?? event.request?.model ?? event.model;
17405
17766
  }
17406
17767
  function flueTurnProvider(event) {
17407
17768
  return event.request?.providerName ?? event.provider ?? event.request?.providerId;
@@ -17416,7 +17777,7 @@ function flueTurnOutput(event) {
17416
17777
  return event.response?.output ?? event.output;
17417
17778
  }
17418
17779
  function flueTurnStopReason(event) {
17419
- return event.response?.stopReason ?? event.stopReason;
17780
+ return event.response?.finishReason ?? event.response?.stopReason ?? event.stopReason;
17420
17781
  }
17421
17782
  function flueTurnError(event) {
17422
17783
  return event.response?.error ?? event.response?.errorInfo?.message ?? event.error;
@@ -17431,6 +17792,9 @@ function flueToolInput(event) {
17431
17792
  return event.input;
17432
17793
  }
17433
17794
  function flueToolOutput(event) {
17795
+ if (Object.hasOwn(event, "effectiveResult")) {
17796
+ return event.effectiveResult;
17797
+ }
17434
17798
  return event.output !== void 0 ? event.output : event.result;
17435
17799
  }
17436
17800
  function flueToolError(event) {
@@ -17438,10 +17802,36 @@ function flueToolError(event) {
17438
17802
  }
17439
17803
  function operationOutput(event) {
17440
17804
  if (event.operationKind === "prompt" || event.operationKind === "skill") {
17441
- return llmResultFromOperationResult(event.result);
17805
+ return outputFromAgentInvocation(event.agentOutput) ?? llmResultFromOperationResult(event.result);
17442
17806
  }
17443
17807
  return event.result ?? (event.operationKind === "compact" ? { completed: true } : void 0);
17444
17808
  }
17809
+ function outputFromAgentInvocation(output) {
17810
+ if (output?.type === "text") {
17811
+ return output.text;
17812
+ }
17813
+ if (output?.type === "data") {
17814
+ return output.data;
17815
+ }
17816
+ return void 0;
17817
+ }
17818
+ function outputFromAgentTurn(output) {
17819
+ if (!isObjectLike(output)) {
17820
+ return output;
17821
+ }
17822
+ const content = Reflect.get(output, "content");
17823
+ if (!Array.isArray(content)) {
17824
+ return output;
17825
+ }
17826
+ const text = content.flatMap((part) => {
17827
+ if (!isObjectLike(part) || Reflect.get(part, "type") !== "text") {
17828
+ return [];
17829
+ }
17830
+ const value = Reflect.get(part, "text");
17831
+ return typeof value === "string" ? [value] : [];
17832
+ });
17833
+ return text.length > 0 ? text.join("") : output;
17834
+ }
17445
17835
  function llmResultFromOperationResult(result) {
17446
17836
  if (!isObjectLike(result)) {
17447
17837
  return result;
@@ -17516,6 +17906,21 @@ function startFlueSpan(parent, args) {
17516
17906
  withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE)
17517
17907
  );
17518
17908
  }
17909
+ function startFlueRootSpan(args) {
17910
+ const state = _internalGetGlobalState();
17911
+ const spanId = state.idGenerator.getSpanId();
17912
+ const rootSpanId = state.idGenerator.shareRootSpanId() ? spanId : state.idGenerator.getTraceId();
17913
+ return withCurrent(
17914
+ NOOP_SPAN,
17915
+ () => startSpan({
17916
+ ...withSpanInstrumentationName(args, INSTRUMENTATION_NAMES.FLUE),
17917
+ parentSpanIds: { parentSpanIds: [], rootSpanId },
17918
+ spanId,
17919
+ state
17920
+ }),
17921
+ state
17922
+ );
17923
+ }
17519
17924
  function runWithCurrentSpanStore(span, next) {
17520
17925
  const state = _internalGetGlobalState();
17521
17926
  const contextManager = state?.contextManager;
@@ -17540,7 +17945,7 @@ function safeEnd(span, endTime) {
17540
17945
  }
17541
17946
  }
17542
17947
  function logInstrumentationError(label, error) {
17543
- console.error(`Error in ${label} instrumentation:`, error);
17948
+ debugLogger.debug(`Error in ${label} instrumentation:`, error);
17544
17949
  }
17545
17950
 
17546
17951
  // src/wrappers/langchain/callback-handler.ts
@@ -19011,12 +19416,30 @@ function logInstrumentationError2(context, error) {
19011
19416
 
19012
19417
  // src/wrappers/anthropic-tokens-util.ts
19013
19418
  function finalizeAnthropicTokens(metrics) {
19014
- const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + (metrics.prompt_cache_creation_tokens || 0);
19015
- return {
19419
+ const hasSplitCacheCreationTokens = metrics.prompt_cache_creation_5m_tokens !== void 0 || metrics.prompt_cache_creation_1h_tokens !== void 0;
19420
+ const splitCacheCreationTokens = (metrics.prompt_cache_creation_5m_tokens || 0) + (metrics.prompt_cache_creation_1h_tokens || 0);
19421
+ const aggregateCacheCreationTokens = metrics.prompt_cache_creation_tokens || 0;
19422
+ const effectiveCacheCreationTokens = Math.max(
19423
+ aggregateCacheCreationTokens,
19424
+ splitCacheCreationTokens
19425
+ );
19426
+ const prompt_tokens = (metrics.prompt_tokens || 0) + (metrics.prompt_cached_tokens || 0) + effectiveCacheCreationTokens;
19427
+ const finalized = {
19016
19428
  ...metrics,
19017
19429
  prompt_tokens,
19018
19430
  tokens: prompt_tokens + (metrics.completion_tokens || 0)
19019
19431
  };
19432
+ if (hasSplitCacheCreationTokens && splitCacheCreationTokens >= aggregateCacheCreationTokens) {
19433
+ delete finalized.prompt_cache_creation_tokens;
19434
+ }
19435
+ return finalized;
19436
+ }
19437
+ function toNumericMetrics(metrics) {
19438
+ return Object.fromEntries(
19439
+ Object.entries(metrics).filter(
19440
+ (entry) => entry[1] !== void 0
19441
+ )
19442
+ );
19020
19443
  }
19021
19444
  function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens = 0) {
19022
19445
  const cacheTokens = {};
@@ -19037,6 +19460,7 @@ var AnthropicPlugin = class extends BasePlugin {
19037
19460
  onEnable() {
19038
19461
  this.subscribeToAnthropicChannels();
19039
19462
  this.subscribeToAnthropicToolRunner();
19463
+ this.subscribeToAnthropicSessionStreams();
19040
19464
  }
19041
19465
  onDisable() {
19042
19466
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
@@ -19154,7 +19578,411 @@ var AnthropicPlugin = class extends BasePlugin {
19154
19578
  tracingChannel.unsubscribe(handlers);
19155
19579
  });
19156
19580
  }
19581
+ subscribeToAnthropicSessionStreams() {
19582
+ this.subscribeToAnthropicSessionStream(
19583
+ anthropicChannels.betaSessionsEventsStream,
19584
+ false
19585
+ );
19586
+ this.subscribeToAnthropicSessionStream(
19587
+ anthropicChannels.betaSessionsThreadsEventsStream,
19588
+ true
19589
+ );
19590
+ }
19591
+ subscribeToAnthropicSessionStream(channel, isThread) {
19592
+ const tracingChannel = channel.tracingChannel();
19593
+ const pending = /* @__PURE__ */ new WeakSet();
19594
+ const handlers = {
19595
+ start: (event) => {
19596
+ if (isAutoInstrumentationSuppressed()) {
19597
+ return;
19598
+ }
19599
+ pending.add(event);
19600
+ },
19601
+ asyncEnd: (event) => {
19602
+ if (!pending.delete(event)) {
19603
+ return;
19604
+ }
19605
+ const stream = event.result;
19606
+ if (!isAsyncIterable(stream)) {
19607
+ return;
19608
+ }
19609
+ registerAnthropicSessionStreamCollector(stream, () => {
19610
+ wrapAnthropicSessionEventStream(stream, isThread);
19611
+ });
19612
+ },
19613
+ error: (event) => {
19614
+ pending.delete(event);
19615
+ }
19616
+ };
19617
+ tracingChannel.subscribe(handlers);
19618
+ this.unsubscribers.push(() => tracingChannel.unsubscribe(handlers));
19619
+ }
19157
19620
  };
19621
+ function wrapAnthropicSessionEventStream(stream, isThread) {
19622
+ const state = {
19623
+ history: [],
19624
+ isThread,
19625
+ pendingInput: [],
19626
+ seenEventIds: /* @__PURE__ */ new Set()
19627
+ };
19628
+ patchStreamIfNeeded(stream, {
19629
+ onChunk: (event) => handleAnthropicSessionEvent(state, event),
19630
+ onComplete: () => finalizeAnthropicSessionTurn(state),
19631
+ onError: (error) => finalizeAnthropicSessionTurn(state, error)
19632
+ });
19633
+ return stream;
19634
+ }
19635
+ function handleAnthropicSessionEvent(state, event) {
19636
+ try {
19637
+ if (typeof event.id === "string" && event.type !== "event_delta" && state.seenEventIds.has(event.id)) {
19638
+ return;
19639
+ }
19640
+ if (typeof event.id === "string" && event.type !== "event_delta") {
19641
+ state.seenEventIds.add(event.id);
19642
+ }
19643
+ switch (event.type) {
19644
+ case "user.message":
19645
+ case "system.message":
19646
+ recordAnthropicSessionInput(
19647
+ state,
19648
+ event
19649
+ );
19650
+ break;
19651
+ case "session.status_running":
19652
+ if (!state.isThread) {
19653
+ ensureAnthropicSessionTurn(state);
19654
+ }
19655
+ break;
19656
+ case "session.thread_status_running":
19657
+ if (state.isThread) {
19658
+ ensureAnthropicSessionTurn(state);
19659
+ }
19660
+ break;
19661
+ case "span.model_request_start":
19662
+ if (typeof event.id === "string") {
19663
+ startAnthropicSessionModel(state, event.id);
19664
+ }
19665
+ break;
19666
+ case "event_delta":
19667
+ recordAnthropicSessionFirstToken(state, event);
19668
+ break;
19669
+ case "agent.message":
19670
+ recordAnthropicSessionMessage(
19671
+ state,
19672
+ event
19673
+ );
19674
+ break;
19675
+ case "agent.custom_tool_use":
19676
+ case "agent.mcp_tool_use":
19677
+ case "agent.tool_use":
19678
+ startAnthropicSessionTool(state, event);
19679
+ break;
19680
+ case "user.tool_confirmation":
19681
+ recordAnthropicSessionToolConfirmation(state, event);
19682
+ break;
19683
+ case "agent.mcp_tool_result":
19684
+ case "agent.tool_result":
19685
+ case "user.custom_tool_result":
19686
+ case "user.tool_result":
19687
+ finalizeAnthropicSessionTool(
19688
+ state,
19689
+ event
19690
+ );
19691
+ break;
19692
+ case "span.model_request_end":
19693
+ finalizeAnthropicSessionModel(
19694
+ state,
19695
+ event
19696
+ );
19697
+ break;
19698
+ case "session.status_idle":
19699
+ case "session.thread_status_idle": {
19700
+ if (event.type === "session.status_idle" && state.isThread || event.type === "session.thread_status_idle" && !state.isThread) {
19701
+ break;
19702
+ }
19703
+ const stopReason = isObject(event.stop_reason) ? event.stop_reason.type : void 0;
19704
+ if (stopReason === "end_turn") {
19705
+ finalizeAnthropicSessionTurn(state);
19706
+ } else if (stopReason === "retries_exhausted") {
19707
+ finalizeAnthropicSessionTurn(
19708
+ state,
19709
+ "Anthropic session retries exhausted"
19710
+ );
19711
+ }
19712
+ break;
19713
+ }
19714
+ case "session.error":
19715
+ finalizeAnthropicSessionTurn(state, event.error);
19716
+ break;
19717
+ case "session.deleted":
19718
+ case "session.status_terminated":
19719
+ case "session.thread_status_terminated":
19720
+ if (event.type === "session.deleted" || event.type === "session.status_terminated" && !state.isThread || event.type === "session.thread_status_terminated" && state.isThread) {
19721
+ finalizeAnthropicSessionTurn(state);
19722
+ }
19723
+ break;
19724
+ default:
19725
+ break;
19726
+ }
19727
+ } catch (error) {
19728
+ debugLogger.debug("Error processing Anthropic Sessions event:", error);
19729
+ }
19730
+ }
19731
+ function ensureAnthropicSessionTurn(state) {
19732
+ if (state.activeTurn) {
19733
+ return state.activeTurn;
19734
+ }
19735
+ const input = state.pendingInput;
19736
+ state.pendingInput = [];
19737
+ const span = startSpan(
19738
+ withSpanInstrumentationName(
19739
+ {
19740
+ event: {
19741
+ ...input.length > 0 ? { input } : {},
19742
+ metadata: { provider: "anthropic" }
19743
+ },
19744
+ name: state.isThread ? "anthropic.beta.sessions.thread.turn" : "anthropic.beta.sessions.turn",
19745
+ spanAttributes: { type: "task" /* TASK */ }
19746
+ },
19747
+ INSTRUMENTATION_NAMES.ANTHROPIC
19748
+ )
19749
+ );
19750
+ state.activeTurn = {
19751
+ activeTools: /* @__PURE__ */ new Map(),
19752
+ input: input.slice(),
19753
+ metrics: {},
19754
+ span
19755
+ };
19756
+ return state.activeTurn;
19757
+ }
19758
+ function recordAnthropicSessionInput(state, event) {
19759
+ const content = processAttachmentsInInput(event.content);
19760
+ const message = {
19761
+ role: event.type === "system.message" ? "system" : "user",
19762
+ content
19763
+ };
19764
+ state.history.push(message);
19765
+ if (state.activeTurn) {
19766
+ state.activeTurn.input.push(message);
19767
+ } else {
19768
+ state.pendingInput.push(message);
19769
+ }
19770
+ }
19771
+ function startAnthropicSessionModel(state, startEventId) {
19772
+ const turn = ensureAnthropicSessionTurn(state);
19773
+ if (turn.activeModel) {
19774
+ finalizeAnthropicSessionModelState(state, turn);
19775
+ }
19776
+ const span = withCurrent(
19777
+ turn.span,
19778
+ () => startSpan(
19779
+ withSpanInstrumentationName(
19780
+ {
19781
+ event: {
19782
+ ...state.history.length > 0 ? { input: state.history.slice() } : {},
19783
+ metadata: { provider: "anthropic" }
19784
+ },
19785
+ name: "anthropic.messages.create",
19786
+ spanAttributes: { type: "llm" /* LLM */ }
19787
+ },
19788
+ INSTRUMENTATION_NAMES.ANTHROPIC
19789
+ )
19790
+ )
19791
+ );
19792
+ turn.activeModel = {
19793
+ output: [],
19794
+ span,
19795
+ startEventId,
19796
+ startTime: getCurrentUnixTimestamp()
19797
+ };
19798
+ }
19799
+ function recordAnthropicSessionFirstToken(state, event) {
19800
+ const model = state.activeTurn?.activeModel;
19801
+ if (!model || model.firstTokenTime !== void 0 || !isObject(event.delta) || !isObject(event.delta.content) || typeof event.delta.content.text !== "string") {
19802
+ return;
19803
+ }
19804
+ model.firstTokenTime = getCurrentUnixTimestamp();
19805
+ }
19806
+ function recordAnthropicSessionMessage(state, event) {
19807
+ const turn = ensureAnthropicSessionTurn(state);
19808
+ const content = processAttachmentsInInput(
19809
+ event.content
19810
+ );
19811
+ if (turn.activeModel) {
19812
+ turn.activeModel.output.push(...content);
19813
+ } else {
19814
+ const output = { role: "assistant", content };
19815
+ turn.lastOutput = output;
19816
+ state.history.push(output);
19817
+ }
19818
+ }
19819
+ function startAnthropicSessionTool(state, event) {
19820
+ const turn = ensureAnthropicSessionTurn(state);
19821
+ if (turn.activeModel) {
19822
+ turn.activeModel.output.push({
19823
+ type: "tool_use",
19824
+ id: event.id,
19825
+ name: event.name,
19826
+ input: event.input
19827
+ });
19828
+ }
19829
+ const existing = turn.activeTools.get(event.id);
19830
+ if (existing) {
19831
+ existing.span.end();
19832
+ turn.activeTools.delete(event.id);
19833
+ }
19834
+ const span = withCurrent(
19835
+ turn.span,
19836
+ () => startSpan(
19837
+ withSpanInstrumentationName(
19838
+ {
19839
+ event: { input: event.input },
19840
+ name: event.name,
19841
+ spanAttributes: { type: "tool" /* TOOL */ }
19842
+ },
19843
+ INSTRUMENTATION_NAMES.ANTHROPIC
19844
+ )
19845
+ )
19846
+ );
19847
+ const toolState = {
19848
+ approval: event.evaluated_permission === "allow" ? "approved" : event.evaluated_permission === "deny" ? "denied" : void 0,
19849
+ span
19850
+ };
19851
+ turn.activeTools.set(event.id, toolState);
19852
+ if (toolState.approval === "denied") {
19853
+ finalizeAnthropicSessionToolState(toolState);
19854
+ turn.activeTools.delete(event.id);
19855
+ }
19856
+ }
19857
+ function recordAnthropicSessionToolConfirmation(state, event) {
19858
+ if (typeof event.tool_use_id !== "string" || event.result !== "allow" && event.result !== "deny") {
19859
+ return;
19860
+ }
19861
+ const turn = state.activeTurn;
19862
+ const tool = turn?.activeTools.get(event.tool_use_id);
19863
+ if (!turn || !tool) {
19864
+ return;
19865
+ }
19866
+ tool.approval = event.result === "allow" ? "approved" : "denied";
19867
+ if (tool.approval === "denied") {
19868
+ finalizeAnthropicSessionToolState(tool);
19869
+ turn.activeTools.delete(event.tool_use_id);
19870
+ }
19871
+ }
19872
+ function finalizeAnthropicSessionTool(state, event) {
19873
+ const toolUseId = event.tool_use_id ?? event.mcp_tool_use_id ?? event.custom_tool_use_id;
19874
+ if (!toolUseId) {
19875
+ return;
19876
+ }
19877
+ const content = processAttachmentsInInput(event.content);
19878
+ const turn = state.activeTurn;
19879
+ const tool = turn?.activeTools.get(toolUseId);
19880
+ if (turn && tool) {
19881
+ finalizeAnthropicSessionToolState(tool, event, content);
19882
+ turn.activeTools.delete(toolUseId);
19883
+ }
19884
+ const toolResult = {
19885
+ type: "tool_result",
19886
+ tool_use_id: toolUseId,
19887
+ ...content !== void 0 ? { content } : {},
19888
+ ...event.is_error === true ? { is_error: true } : {}
19889
+ };
19890
+ state.history.push({
19891
+ role: "user",
19892
+ content: [toolResult]
19893
+ });
19894
+ }
19895
+ function finalizeAnthropicSessionToolState(state, event, content = event?.content) {
19896
+ safeAnthropicSessionLog(state.span, {
19897
+ ...event?.is_error === true ? {
19898
+ error: content ?? "Anthropic session tool execution failed"
19899
+ } : {},
19900
+ ...state.approval ? { metadata: { tool_approval: state.approval } } : {},
19901
+ ...content !== void 0 ? { output: content } : {}
19902
+ });
19903
+ state.span.end();
19904
+ }
19905
+ function finalizeAnthropicSessionModel(state, event) {
19906
+ const turn = state.activeTurn;
19907
+ const model = turn?.activeModel;
19908
+ if (!turn || !model || model.startEventId !== event.model_request_start_id) {
19909
+ return;
19910
+ }
19911
+ finalizeAnthropicSessionModelState(state, turn, event);
19912
+ }
19913
+ function finalizeAnthropicSessionModelState(state, turn, event) {
19914
+ const model = turn.activeModel;
19915
+ if (!model) {
19916
+ return;
19917
+ }
19918
+ turn.activeModel = void 0;
19919
+ const metrics = event ? parseAnthropicSessionModelUsage(event.model_usage) : {};
19920
+ if (model.firstTokenTime !== void 0) {
19921
+ metrics.time_to_first_token = model.firstTokenTime - model.startTime;
19922
+ }
19923
+ const output = model.output.length > 0 ? { role: "assistant", content: model.output } : void 0;
19924
+ safeAnthropicSessionLog(model.span, {
19925
+ ...event?.is_error ? { error: "Anthropic session model request failed" } : {},
19926
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
19927
+ ...output ? { output } : {}
19928
+ });
19929
+ model.span.end();
19930
+ if (output) {
19931
+ turn.lastOutput = output;
19932
+ state.history.push(output);
19933
+ }
19934
+ for (const key of [
19935
+ "prompt_tokens",
19936
+ "completion_tokens",
19937
+ "tokens",
19938
+ "prompt_cached_tokens",
19939
+ "prompt_cache_creation_tokens"
19940
+ ]) {
19941
+ const value = metrics[key];
19942
+ if (typeof value === "number") {
19943
+ turn.metrics[key] = (turn.metrics[key] ?? 0) + value;
19944
+ }
19945
+ }
19946
+ }
19947
+ function parseAnthropicSessionModelUsage(usage) {
19948
+ const finalized = finalizeAnthropicTokens({
19949
+ completion_tokens: usage.output_tokens,
19950
+ prompt_cache_creation_tokens: usage.cache_creation_input_tokens,
19951
+ prompt_cached_tokens: usage.cache_read_input_tokens,
19952
+ prompt_tokens: usage.input_tokens
19953
+ });
19954
+ return Object.fromEntries(
19955
+ Object.entries(finalized).filter(
19956
+ (entry) => entry[1] !== void 0
19957
+ )
19958
+ );
19959
+ }
19960
+ function finalizeAnthropicSessionTurn(state, error) {
19961
+ const turn = state.activeTurn;
19962
+ if (!turn) {
19963
+ return;
19964
+ }
19965
+ state.activeTurn = void 0;
19966
+ finalizeAnthropicSessionModelState(state, turn);
19967
+ for (const tool of turn.activeTools.values()) {
19968
+ finalizeAnthropicSessionToolState(tool);
19969
+ }
19970
+ turn.activeTools.clear();
19971
+ safeAnthropicSessionLog(turn.span, {
19972
+ ...error !== void 0 ? { error: error instanceof Error ? error : toLoggedError(error) } : {},
19973
+ ...turn.input.length > 0 ? { input: turn.input } : {},
19974
+ ...turn.lastOutput ? { output: turn.lastOutput } : {},
19975
+ ...Object.keys(turn.metrics).length > 0 ? { metrics: turn.metrics } : {}
19976
+ });
19977
+ turn.span.end();
19978
+ }
19979
+ function safeAnthropicSessionLog(span, event) {
19980
+ try {
19981
+ span.log(event);
19982
+ } catch (error) {
19983
+ debugLogger.debug("Error logging Anthropic Sessions span:", error);
19984
+ }
19985
+ }
19158
19986
  function parseMetricsFromUsage2(usage) {
19159
19987
  if (!usage) {
19160
19988
  return {};
@@ -19170,6 +19998,18 @@ function parseMetricsFromUsage2(usage) {
19170
19998
  saveIfExistsTo("output_tokens", "completion_tokens");
19171
19999
  saveIfExistsTo("cache_read_input_tokens", "prompt_cached_tokens");
19172
20000
  saveIfExistsTo("cache_creation_input_tokens", "prompt_cache_creation_tokens");
20001
+ if (isObject(usage.cache_creation)) {
20002
+ const cacheCreation = usage.cache_creation;
20003
+ for (const [source, target] of [
20004
+ ["ephemeral_5m_input_tokens", "prompt_cache_creation_5m_tokens"],
20005
+ ["ephemeral_1h_input_tokens", "prompt_cache_creation_1h_tokens"]
20006
+ ]) {
20007
+ const value = cacheCreation[source];
20008
+ if (typeof value === "number") {
20009
+ metrics[target] = value;
20010
+ }
20011
+ }
20012
+ }
19173
20013
  if (isObject(usage.server_tool_use)) {
19174
20014
  for (const [name, value] of Object.entries(usage.server_tool_use)) {
19175
20015
  if (typeof value === "number") {
@@ -20141,37 +20981,97 @@ function seedTaskToolUseIdMapping(taskIdToToolUseId, message) {
20141
20981
  taskIdToToolUseId.set(message.task_id, message.tool_use_id);
20142
20982
  }
20143
20983
  }
20144
- function extractUsageFromMessage(message) {
20145
- const metrics = {};
20146
- let usage;
20147
- if (message.type === "assistant") {
20148
- usage = message.message?.usage;
20149
- } else if (message.type === "result") {
20150
- usage = message.usage;
20151
- }
20984
+ function tokenCount(value) {
20985
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : void 0;
20986
+ }
20987
+ function copyUsage(usage) {
20152
20988
  if (!usage || typeof usage !== "object") {
20153
- return metrics;
20989
+ return void 0;
20990
+ }
20991
+ const copy = {};
20992
+ for (const key of [
20993
+ "input_tokens",
20994
+ "output_tokens",
20995
+ "cache_read_input_tokens",
20996
+ "cache_creation_input_tokens"
20997
+ ]) {
20998
+ const value = tokenCount(Reflect.get(usage, key));
20999
+ if (value !== void 0) {
21000
+ copy[key] = value;
21001
+ }
21002
+ }
21003
+ const cacheCreation = Reflect.get(usage, "cache_creation");
21004
+ if (cacheCreation && typeof cacheCreation === "object") {
21005
+ const cacheCreationCopy = {};
21006
+ for (const key of [
21007
+ "ephemeral_5m_input_tokens",
21008
+ "ephemeral_1h_input_tokens"
21009
+ ]) {
21010
+ const value = tokenCount(Reflect.get(cacheCreation, key));
21011
+ if (value !== void 0) {
21012
+ cacheCreationCopy[key] = value;
21013
+ }
21014
+ }
21015
+ if (Object.keys(cacheCreationCopy).length > 0) {
21016
+ copy.cache_creation = cacheCreationCopy;
21017
+ }
21018
+ }
21019
+ return Object.keys(copy).length > 0 ? copy : void 0;
21020
+ }
21021
+ function mergeUsage(base, override) {
21022
+ if (!base || !override) {
21023
+ return override ?? base;
21024
+ }
21025
+ const cacheCreation = base.cache_creation || override.cache_creation ? { ...base.cache_creation, ...override.cache_creation } : void 0;
21026
+ return {
21027
+ ...base,
21028
+ ...override,
21029
+ ...cacheCreation && { cache_creation: cacheCreation }
21030
+ };
21031
+ }
21032
+ function extractUsage(usage, includeOutput) {
21033
+ const metrics = {};
21034
+ if (!usage) {
21035
+ return {};
20154
21036
  }
20155
21037
  const inputTokens = getNumberProperty(usage, "input_tokens");
20156
21038
  if (inputTokens !== void 0) {
20157
21039
  metrics.prompt_tokens = inputTokens;
20158
21040
  }
20159
- const outputTokens = getNumberProperty(usage, "output_tokens");
20160
- if (outputTokens !== void 0) {
20161
- metrics.completion_tokens = outputTokens;
21041
+ if (includeOutput) {
21042
+ const outputTokens = getNumberProperty(usage, "output_tokens");
21043
+ if (outputTokens !== void 0) {
21044
+ metrics.completion_tokens = outputTokens;
21045
+ }
20162
21046
  }
20163
21047
  const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
20164
21048
  const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
20165
- if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
20166
- Object.assign(
20167
- metrics,
20168
- extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
20169
- );
21049
+ Object.assign(
21050
+ metrics,
21051
+ extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
21052
+ );
21053
+ const cacheCreation5mTokens = getNumberProperty(
21054
+ usage.cache_creation,
21055
+ "ephemeral_5m_input_tokens"
21056
+ );
21057
+ const cacheCreation1hTokens = getNumberProperty(
21058
+ usage.cache_creation,
21059
+ "ephemeral_1h_input_tokens"
21060
+ );
21061
+ if (cacheCreation5mTokens !== void 0) {
21062
+ metrics.prompt_cache_creation_5m_tokens = cacheCreation5mTokens;
20170
21063
  }
20171
- if (Object.keys(metrics).length > 0) {
20172
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
21064
+ if (cacheCreation1hTokens !== void 0) {
21065
+ metrics.prompt_cache_creation_1h_tokens = cacheCreation1hTokens;
20173
21066
  }
20174
- return metrics;
21067
+ if (Object.keys(metrics).length === 0) {
21068
+ return {};
21069
+ }
21070
+ const finalized = finalizeAnthropicTokens(metrics);
21071
+ if (metrics.completion_tokens === void 0) {
21072
+ delete finalized.tokens;
21073
+ }
21074
+ return toNumericMetrics(finalized);
20175
21075
  }
20176
21076
  function buildLLMInput(promptMessages, conversationHistory) {
20177
21077
  const inputParts = [...promptMessages, ...conversationHistory];
@@ -20205,16 +21105,16 @@ function buildRootPromptMessages(prompt, capturedPromptMessages) {
20205
21105
  function formatCapturedMessages(messages) {
20206
21106
  return messages.length > 0 ? messages : [];
20207
21107
  }
20208
- async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
21108
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, usage, hasFinalOutputUsage, existingSpan) {
20209
21109
  if (messages.length === 0) {
20210
21110
  return void 0;
20211
21111
  }
20212
21112
  const lastMessage = messages[messages.length - 1];
20213
- if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
21113
+ if (lastMessage.type !== "assistant") {
20214
21114
  return void 0;
20215
21115
  }
20216
- const model = lastMessage.message.model || options.model;
20217
- const usage = extractUsageFromMessage(lastMessage);
21116
+ const model = lastMessage.message?.model || options.model;
21117
+ const metrics = options.includePartialMessages ? extractUsage(usage, hasFinalOutputUsage) : {};
20218
21118
  const input = buildLLMInput(promptMessages, conversationHistory);
20219
21119
  const outputs = messages.map(
20220
21120
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
@@ -20236,8 +21136,8 @@ async function createLLMSpanForMessages(messages, promptMessages, conversationHi
20236
21136
  );
20237
21137
  span.log({
20238
21138
  input,
20239
- metadata: model ? { model } : void 0,
20240
- metrics: usage,
21139
+ metadata: { ...model && { model }, provider: "anthropic" },
21140
+ ...Object.keys(metrics).length > 0 ? { metrics } : {},
20241
21141
  output: outputs
20242
21142
  });
20243
21143
  const spanExport = await span.export();
@@ -20327,11 +21227,17 @@ function prepareLocalToolHandlersInMcpServers(mcpServers) {
20327
21227
  }
20328
21228
  return { hasLocalToolHandlers, localToolHookNames };
20329
21229
  }
20330
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
21230
+ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20331
21231
  const preToolUse = async (input, toolUseID) => {
20332
21232
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
20333
21233
  return {};
20334
21234
  }
21235
+ if (!toolUseToParent.has(toolUseID) && input.agent_id) {
21236
+ const parentToolUseId = taskIdToToolUseId.get(input.agent_id);
21237
+ if (parentToolUseId) {
21238
+ toolUseToParent.set(toolUseID, parentToolUseId);
21239
+ }
21240
+ }
20335
21241
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
20336
21242
  return {};
20337
21243
  }
@@ -20527,9 +21433,6 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
20527
21433
  }
20528
21434
  const metadata = {
20529
21435
  ...subAgentDetailsToMetadata(details),
20530
- ...input.agent_transcript_path && {
20531
- "claude_agent_sdk.agent_transcript_path": input.agent_transcript_path
20532
- },
20533
21436
  "claude_agent_sdk.stop_hook_active": input.stop_hook_active
20534
21437
  };
20535
21438
  try {
@@ -20551,7 +21454,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
20551
21454
  subagentStop
20552
21455
  };
20553
21456
  }
20554
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
21457
+ function injectTracingHooks(options, resolveParentSpan, taskIdToToolUseId, toolUseToParent, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
20555
21458
  const {
20556
21459
  preToolUse,
20557
21460
  postToolUse,
@@ -20560,6 +21463,8 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
20560
21463
  subagentStop
20561
21464
  } = createToolTracingHooks(
20562
21465
  resolveParentSpan,
21466
+ taskIdToToolUseId,
21467
+ toolUseToParent,
20563
21468
  activeToolSpans,
20564
21469
  options.mcpServers,
20565
21470
  localToolHookNames,
@@ -20641,6 +21546,13 @@ async function finalizeCurrentMessageGroup(state) {
20641
21546
  }
20642
21547
  }
20643
21548
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
21549
+ const lastMessage = state.currentMessages[state.currentMessages.length - 1];
21550
+ const messageId = lastMessage?.message?.id;
21551
+ const usage = state.options.includePartialMessages ? mergeUsage(
21552
+ copyUsage(lastMessage?.message?.usage),
21553
+ messageId ? state.usageByMessageId.get(messageId) : void 0
21554
+ ) : void 0;
21555
+ const hasFinalOutputUsage = messageId !== void 0 && state.finalOutputUsageMessageIds.has(messageId);
20644
21556
  const llmSpanResult = await createLLMSpanForMessages(
20645
21557
  state.currentMessages,
20646
21558
  promptMessages,
@@ -20648,6 +21560,8 @@ async function finalizeCurrentMessageGroup(state) {
20648
21560
  state.options,
20649
21561
  state.currentMessageStartTime,
20650
21562
  parentSpan,
21563
+ usage,
21564
+ hasFinalOutputUsage,
20651
21565
  existingLlmSpan
20652
21566
  );
20653
21567
  if (llmSpanResult) {
@@ -20665,9 +21579,17 @@ async function finalizeCurrentMessageGroup(state) {
20665
21579
  }
20666
21580
  }
20667
21581
  state.activeLlmSpansByParentToolUse.delete(parentKey);
20668
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
20669
- if (lastMessage?.message?.usage) {
20670
- state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
21582
+ if (messageId) {
21583
+ state.usageByMessageId.delete(messageId);
21584
+ state.finalOutputUsageMessageIds.delete(messageId);
21585
+ for (const [
21586
+ parent,
21587
+ activeMessageId
21588
+ ] of state.activePartialMessageIdByParentKey) {
21589
+ if (activeMessageId === messageId) {
21590
+ state.activePartialMessageIdByParentKey.delete(parent);
21591
+ }
21592
+ }
20671
21593
  }
20672
21594
  state.currentMessages.length = 0;
20673
21595
  }
@@ -20758,6 +21680,10 @@ async function ensureActiveLlmSpanForParentToolUse(rootSpan, activeLlmSpansByPar
20758
21680
  );
20759
21681
  llmParentSpan = await subAgentSpan.export();
20760
21682
  }
21683
+ const racedLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
21684
+ if (racedLlmSpan) {
21685
+ return racedLlmSpan;
21686
+ }
20761
21687
  const llmSpan = startSpan(
20762
21688
  withSpanInstrumentationName(
20763
21689
  {
@@ -20877,7 +21803,49 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
20877
21803
  }
20878
21804
  return true;
20879
21805
  }
21806
+ function handlePartialUsageMessage(state, message) {
21807
+ if (message.type !== "stream_event") {
21808
+ return false;
21809
+ }
21810
+ const event = message.event;
21811
+ if (!event || typeof event !== "object") {
21812
+ return true;
21813
+ }
21814
+ const parentKey = llmParentKey(message.parent_tool_use_id ?? null);
21815
+ if (event.type === "message_start") {
21816
+ const messageId2 = event.message?.id;
21817
+ const usage = copyUsage(event.message?.usage);
21818
+ if (messageId2) {
21819
+ state.activePartialMessageIdByParentKey.set(parentKey, messageId2);
21820
+ if (usage) {
21821
+ state.usageByMessageId.set(messageId2, usage);
21822
+ }
21823
+ }
21824
+ return true;
21825
+ }
21826
+ const messageId = state.activePartialMessageIdByParentKey.get(parentKey);
21827
+ if (!messageId) {
21828
+ return true;
21829
+ }
21830
+ if (event.type === "message_delta") {
21831
+ const update = copyUsage(event.usage);
21832
+ if (update) {
21833
+ const usage = state.usageByMessageId.get(messageId) ?? {};
21834
+ Object.assign(usage, update);
21835
+ state.usageByMessageId.set(messageId, usage);
21836
+ if (update.output_tokens !== void 0) {
21837
+ state.finalOutputUsageMessageIds.add(messageId);
21838
+ }
21839
+ }
21840
+ } else if (event.type === "message_stop") {
21841
+ state.activePartialMessageIdByParentKey.delete(parentKey);
21842
+ }
21843
+ return true;
21844
+ }
20880
21845
  async function handleStreamMessage(state, message) {
21846
+ if (handlePartialUsageMessage(state, message)) {
21847
+ return;
21848
+ }
20881
21849
  maybeTrackToolUseContext(state, message);
20882
21850
  if (await maybeHandleTaskLifecycleMessage(state, message)) {
20883
21851
  return;
@@ -20924,36 +21892,9 @@ async function handleStreamMessage(state, message) {
20924
21892
  );
20925
21893
  state.currentMessages.push(message);
20926
21894
  }
20927
- if (message.type !== "result" || !message.usage) {
21895
+ if (message.type !== "result") {
20928
21896
  return;
20929
21897
  }
20930
- const finalUsageMetrics = extractUsageFromMessage(message);
20931
- if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
20932
- const lastMessage = state.currentMessages[state.currentMessages.length - 1];
20933
- if (lastMessage?.message?.usage) {
20934
- const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
20935
- if (adjustedTokens >= 0) {
20936
- lastMessage.message.usage.output_tokens = adjustedTokens;
20937
- }
20938
- const resultUsage = message.usage;
20939
- if (resultUsage && typeof resultUsage === "object") {
20940
- const cacheReadTokens = getNumberProperty(
20941
- resultUsage,
20942
- "cache_read_input_tokens"
20943
- );
20944
- if (cacheReadTokens !== void 0) {
20945
- lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
20946
- }
20947
- const cacheCreationTokens = getNumberProperty(
20948
- resultUsage,
20949
- "cache_creation_input_tokens"
20950
- );
20951
- if (cacheCreationTokens !== void 0) {
20952
- lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
20953
- }
20954
- }
20955
- }
20956
- }
20957
21898
  const metadata = {};
20958
21899
  if (message.num_turns !== void 0) {
20959
21900
  metadata.num_turns = message.num_turns;
@@ -20961,8 +21902,12 @@ async function handleStreamMessage(state, message) {
20961
21902
  if (message.session_id !== void 0) {
20962
21903
  metadata.session_id = message.session_id;
20963
21904
  }
20964
- if (Object.keys(metadata).length > 0) {
20965
- state.span.log({ metadata });
21905
+ const metrics = state.options.includePartialMessages ? {} : extractUsage(copyUsage(message.usage), true);
21906
+ if (Object.keys(metadata).length > 0 || Object.keys(metrics).length > 0) {
21907
+ state.span.log({
21908
+ ...Object.keys(metadata).length > 0 ? { metadata } : {},
21909
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
21910
+ });
20966
21911
  }
20967
21912
  }
20968
21913
  async function finalizeQuerySpan(state) {
@@ -20986,6 +21931,9 @@ async function finalizeQuerySpan(state) {
20986
21931
  llmSpan.end();
20987
21932
  }
20988
21933
  state.activeLlmSpansByParentToolUse.clear();
21934
+ state.activePartialMessageIdByParentKey.clear();
21935
+ state.finalOutputUsageMessageIds.clear();
21936
+ state.usageByMessageId.clear();
20989
21937
  for (const toolSpan of state.activeToolSpans.values()) {
20990
21938
  toolSpan.end();
20991
21939
  }
@@ -21110,6 +22058,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21110
22058
  const optionsWithHooks = injectTracingHooks(
21111
22059
  options,
21112
22060
  resolveToolUseParentSpan,
22061
+ taskIdToToolUseId,
22062
+ toolUseToParent,
21113
22063
  activeToolSpans,
21114
22064
  localToolHookNames,
21115
22065
  skipLocalToolHooks,
@@ -21120,8 +22070,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21120
22070
  params.options = optionsWithHooks;
21121
22071
  event.arguments[0] = params;
21122
22072
  spans.set(event, {
21123
- accumulatedOutputTokens: 0,
21124
22073
  activeLlmSpansByParentToolUse,
22074
+ activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
21125
22075
  activeToolSpans,
21126
22076
  conversationHistoryByParentKey,
21127
22077
  capturedPromptMessages,
@@ -21129,6 +22079,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21129
22079
  currentMessageStartTime: startTime,
21130
22080
  currentMessages: [],
21131
22081
  endedSubAgentSpans,
22082
+ finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
21132
22083
  finalResults: [],
21133
22084
  options: optionsWithHooks,
21134
22085
  originalPrompt,
@@ -21144,6 +22095,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21144
22095
  latestLlmParentBySubAgentToolUse,
21145
22096
  latestRootLlmParentRef,
21146
22097
  toolUseToParent,
22098
+ usageByMessageId: /* @__PURE__ */ new Map(),
21147
22099
  localToolContext
21148
22100
  });
21149
22101
  },
@@ -21213,6 +22165,283 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
21213
22165
  }
21214
22166
  };
21215
22167
 
22168
+ // src/instrumentation/plugins/cloudflare-think-plugin.ts
22169
+ var THINK_STATE_ID = /* @__PURE__ */ Symbol.for("braintrust.cloudflare-think.state-id");
22170
+ var CloudflareThinkPlugin = class extends BasePlugin {
22171
+ statesBySpanId = /* @__PURE__ */ new Map();
22172
+ onEnable() {
22173
+ this.subscribeToThinkRuns();
22174
+ this.subscribeToAISDKStreamTextSync();
22175
+ this.subscribeToAISDKStreamTextAsync();
22176
+ }
22177
+ onDisable() {
22178
+ for (const unsubscribe of this.unsubscribers) {
22179
+ unsubscribe();
22180
+ }
22181
+ this.unsubscribers = [];
22182
+ for (const state of this.statesBySpanId.values()) {
22183
+ this.finishState(state);
22184
+ }
22185
+ this.statesBySpanId.clear();
22186
+ }
22187
+ subscribeToThinkRuns() {
22188
+ const channel = cloudflareThinkChannels.runInferenceLoop.tracingChannel();
22189
+ const states = /* @__PURE__ */ new WeakMap();
22190
+ const state = _internalGetGlobalState();
22191
+ const contextManager = state?.contextManager;
22192
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
22193
+ const ensureState2 = (event) => {
22194
+ if (isAutoInstrumentationSuppressed()) {
22195
+ return void 0;
22196
+ }
22197
+ const existing = states.get(event);
22198
+ if (existing) {
22199
+ return existing;
22200
+ }
22201
+ const span = startSpan(
22202
+ withSpanInstrumentationName(
22203
+ {
22204
+ name: "Think.runTurn",
22205
+ spanAttributes: { type: "task" /* TASK */ }
22206
+ },
22207
+ INSTRUMENTATION_NAMES.CLOUDFLARE_THINK
22208
+ )
22209
+ );
22210
+ const runState = {
22211
+ aiResultPatched: false,
22212
+ fallbackInput: extractFallbackInput(event.self?.messages),
22213
+ finalized: false,
22214
+ inputLogged: false,
22215
+ span,
22216
+ startTime: getCurrentUnixTimestamp()
22217
+ };
22218
+ const metadata = {
22219
+ braintrust: {
22220
+ integration_name: "cloudflare-think",
22221
+ sdk_language: "typescript"
22222
+ }
22223
+ };
22224
+ if (typeof event.moduleVersion === "string") {
22225
+ metadata["cloudflare_think.version"] = event.moduleVersion;
22226
+ }
22227
+ span.log({ metadata });
22228
+ states.set(event, runState);
22229
+ if (span.spanId) {
22230
+ this.statesBySpanId.set(span.spanId, runState);
22231
+ }
22232
+ registerCloudflareThinkSpan(span);
22233
+ return runState;
22234
+ };
22235
+ if (contextManager && currentSpanStore && channel.start) {
22236
+ channel.start.bindStore(currentSpanStore, (event) => {
22237
+ const runState = ensureState2(event);
22238
+ return runState ? contextManager.wrapSpanForStore(runState.span) : currentSpanStore.getStore();
22239
+ });
22240
+ this.unsubscribers.push(
22241
+ () => channel.start?.unbindStore(currentSpanStore)
22242
+ );
22243
+ }
22244
+ const handlers = {
22245
+ start: (event) => {
22246
+ ensureState2(event);
22247
+ },
22248
+ asyncEnd: (event) => {
22249
+ const runState = states.get(event);
22250
+ states.delete(event);
22251
+ if (!runState || runState.finalized || runState.aiResultPatched) {
22252
+ return;
22253
+ }
22254
+ this.finishState(runState, void 0, event.result);
22255
+ },
22256
+ error: (event) => {
22257
+ const runState = states.get(event);
22258
+ states.delete(event);
22259
+ if (runState) {
22260
+ this.finishState(runState, event.error);
22261
+ }
22262
+ }
22263
+ };
22264
+ channel.subscribe(handlers);
22265
+ this.unsubscribers.push(() => channel.unsubscribe(handlers));
22266
+ }
22267
+ subscribeToAISDKStreamTextSync() {
22268
+ const channel = aiSDKChannels.streamTextSync.tracingChannel();
22269
+ const handlers = {
22270
+ start: (event) => {
22271
+ this.startAISDKStream(event);
22272
+ },
22273
+ end: (event) => {
22274
+ this.endAISDKStream(event);
22275
+ },
22276
+ error: (event) => {
22277
+ this.errorAISDKStream(event);
22278
+ }
22279
+ };
22280
+ channel.subscribe(handlers);
22281
+ this.unsubscribers.push(() => channel.unsubscribe(handlers));
22282
+ }
22283
+ subscribeToAISDKStreamTextAsync() {
22284
+ const channel = aiSDKChannels.streamText.tracingChannel();
22285
+ const handlers = {
22286
+ start: (event) => {
22287
+ this.startAISDKStream(event);
22288
+ },
22289
+ asyncEnd: (event) => {
22290
+ this.endAISDKStream(event);
22291
+ },
22292
+ error: (event) => {
22293
+ this.errorAISDKStream(event);
22294
+ }
22295
+ };
22296
+ channel.subscribe(handlers);
22297
+ this.unsubscribers.push(() => channel.unsubscribe(handlers));
22298
+ }
22299
+ startAISDKStream(event) {
22300
+ const runState = this.currentState();
22301
+ if (!runState || runState.finalized) {
22302
+ return;
22303
+ }
22304
+ try {
22305
+ const prepared = prepareAISDKAgentCallInput(
22306
+ event.arguments[0],
22307
+ event,
22308
+ runState.span
22309
+ );
22310
+ runState.span.log({
22311
+ input: extractThinkTaskInput(prepared.input),
22312
+ metadata: {
22313
+ ...prepared.metadata,
22314
+ braintrust: {
22315
+ integration_name: "cloudflare-think",
22316
+ sdk_language: "typescript"
22317
+ }
22318
+ }
22319
+ });
22320
+ runState.inputLogged = true;
22321
+ runState.aiEvent = event;
22322
+ Reflect.set(event, THINK_STATE_ID, runState.span.spanId);
22323
+ } catch (error) {
22324
+ debugLogger.error(
22325
+ "Error preparing @cloudflare/think AI SDK tracing:",
22326
+ error
22327
+ );
22328
+ }
22329
+ }
22330
+ endAISDKStream(event) {
22331
+ const runState = this.stateForAISDKEvent(event);
22332
+ if (!runState || runState.finalized) {
22333
+ return;
22334
+ }
22335
+ const patched = patchAISDKStreamingResult({
22336
+ defaultDenyOutputPaths: DEFAULT_DENY_OUTPUT_PATHS,
22337
+ endEvent: event,
22338
+ forceTopLevelMetrics: true,
22339
+ onComplete: () => this.releaseState(runState),
22340
+ result: event.result,
22341
+ span: runState.span,
22342
+ startTime: runState.startTime,
22343
+ transformOutput: extractThinkTaskOutput
22344
+ });
22345
+ runState.aiResultPatched = patched;
22346
+ if (!patched) {
22347
+ this.finishState(runState, void 0, event.result);
22348
+ }
22349
+ }
22350
+ errorAISDKStream(event) {
22351
+ const runState = this.stateForAISDKEvent(event);
22352
+ if (runState) {
22353
+ this.finishState(runState, event.error);
22354
+ }
22355
+ }
22356
+ currentState() {
22357
+ const parentIds = _internalGetGlobalState()?.contextManager.getParentSpanIds()?.spanParents ?? [];
22358
+ for (const parentId of parentIds) {
22359
+ const state = this.statesBySpanId.get(parentId);
22360
+ if (state) {
22361
+ return state;
22362
+ }
22363
+ }
22364
+ return void 0;
22365
+ }
22366
+ stateForAISDKEvent(event) {
22367
+ const spanId = Reflect.get(event, THINK_STATE_ID);
22368
+ return typeof spanId === "string" ? this.statesBySpanId.get(spanId) : void 0;
22369
+ }
22370
+ finishState(state, error, output) {
22371
+ if (state.finalized) {
22372
+ return;
22373
+ }
22374
+ state.finalized = true;
22375
+ try {
22376
+ if (!state.inputLogged && state.fallbackInput !== void 0) {
22377
+ state.span.log({ input: state.fallbackInput });
22378
+ }
22379
+ if (error !== void 0) {
22380
+ state.span.log({ error });
22381
+ } else if (output !== void 0) {
22382
+ state.span.log({ output: extractThinkTaskOutput(output) });
22383
+ }
22384
+ finalizeAISDKChildTracing(state.aiEvent);
22385
+ state.span.end();
22386
+ } finally {
22387
+ this.releaseState(state);
22388
+ }
22389
+ }
22390
+ releaseState(state) {
22391
+ state.finalized = true;
22392
+ unregisterCloudflareThinkSpan(state.span);
22393
+ if (state.span.spanId) {
22394
+ this.statesBySpanId.delete(state.span.spanId);
22395
+ }
22396
+ }
22397
+ };
22398
+ function extractFallbackInput(messages) {
22399
+ if (!Array.isArray(messages) || messages.length === 0) {
22400
+ return void 0;
22401
+ }
22402
+ let latestUserIndex = -1;
22403
+ for (let index = messages.length - 1; index >= 0; index--) {
22404
+ if (messages[index]?.role === "user") {
22405
+ latestUserIndex = index;
22406
+ break;
22407
+ }
22408
+ }
22409
+ const selected = latestUserIndex >= 0 ? messages.slice(latestUserIndex) : [];
22410
+ return selected.map((message) => ({
22411
+ role: message.role,
22412
+ content: message.content ?? message.parts
22413
+ }));
22414
+ }
22415
+ function extractThinkTaskOutput(output) {
22416
+ if (!isObject(output)) {
22417
+ return output;
22418
+ }
22419
+ if (typeof output.text === "string") {
22420
+ return { role: "assistant", content: output.text };
22421
+ }
22422
+ if (output.object !== void 0) {
22423
+ return output.object;
22424
+ }
22425
+ return output;
22426
+ }
22427
+ function extractThinkTaskInput(input) {
22428
+ if (!isObject(input)) {
22429
+ return input;
22430
+ }
22431
+ const system = input.instructions ?? input.system;
22432
+ if (Array.isArray(input.messages)) {
22433
+ return system === void 0 ? input.messages : [{ role: "system", content: system }, ...input.messages];
22434
+ }
22435
+ if (Array.isArray(input.prompt)) {
22436
+ return system === void 0 ? input.prompt : [{ role: "system", content: system }, ...input.prompt];
22437
+ }
22438
+ if (typeof input.prompt === "string") {
22439
+ const messages = [{ role: "user", content: input.prompt }];
22440
+ return system === void 0 ? messages : [{ role: "system", content: system }, ...messages];
22441
+ }
22442
+ return input;
22443
+ }
22444
+
21216
22445
  // src/instrumentation/plugins/cursor-sdk-plugin.ts
21217
22446
  var PATCHED_AGENT = /* @__PURE__ */ Symbol.for("braintrust.cursor-sdk.auto-patched-agent");
21218
22447
  var PATCHED_RUN = /* @__PURE__ */ Symbol.for("braintrust.cursor-sdk.patched-run");
@@ -23257,9 +24486,9 @@ function extractEmbedPromptTokenCount(response) {
23257
24486
  let sawAny = false;
23258
24487
  for (const embedding of embeddings) {
23259
24488
  const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
23260
- const tokenCount = embeddingStats?.tokenCount;
23261
- if (typeof tokenCount === "number" && Number.isFinite(tokenCount)) {
23262
- total += tokenCount;
24489
+ const tokenCount2 = embeddingStats?.tokenCount;
24490
+ if (typeof tokenCount2 === "number" && Number.isFinite(tokenCount2)) {
24491
+ total += tokenCount2;
23263
24492
  sawAny = true;
23264
24493
  }
23265
24494
  }
@@ -26730,6 +27959,450 @@ function aggregateMistralStreamChunks(chunks) {
26730
27959
  };
26731
27960
  }
26732
27961
 
27962
+ // src/instrumentation/plugins/ollama-plugin.ts
27963
+ var OllamaPlugin = class extends BasePlugin {
27964
+ onEnable() {
27965
+ this.unsubscribers.push(
27966
+ traceStreamingChannel(ollamaChannels.chat, {
27967
+ name: "ollama.chat",
27968
+ type: "llm" /* LLM */,
27969
+ extractInput: extractOllamaChatInput,
27970
+ extractOutput: (result, event) => extractOllamaChatOutput(
27971
+ result,
27972
+ countOllamaToolCalls(event?.arguments?.[0]?.messages)
27973
+ ),
27974
+ extractMetadata: extractOllamaResponseMetadata,
27975
+ extractMetrics: extractOllamaMetrics,
27976
+ aggregateChunks: aggregateOllamaChatChunks
27977
+ }),
27978
+ traceStreamingChannel(ollamaChannels.generate, {
27979
+ name: "ollama.generate",
27980
+ type: "llm" /* LLM */,
27981
+ extractInput: extractOllamaGenerateInput,
27982
+ extractOutput: extractOllamaGenerateOutput,
27983
+ extractMetadata: extractOllamaResponseMetadata,
27984
+ extractMetrics: extractOllamaMetrics,
27985
+ aggregateChunks: aggregateOllamaGenerateChunks
27986
+ }),
27987
+ traceAsyncChannel(ollamaChannels.embed, {
27988
+ name: "ollama.embed",
27989
+ type: "llm" /* LLM */,
27990
+ extractInput: extractOllamaEmbedInput,
27991
+ extractOutput: extractOllamaEmbedOutput,
27992
+ extractMetadata: extractOllamaResponseMetadata,
27993
+ extractMetrics: extractOllamaMetrics
27994
+ })
27995
+ );
27996
+ }
27997
+ onDisable() {
27998
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
27999
+ }
28000
+ };
28001
+ function isNonNegativeNumber(value) {
28002
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
28003
+ }
28004
+ function normalizeFinishReason(response, hasToolCalls = false) {
28005
+ if (hasToolCalls) {
28006
+ return "tool_calls";
28007
+ }
28008
+ return response?.done_reason || "stop";
28009
+ }
28010
+ function stringifyArguments(value) {
28011
+ if (typeof value === "string") {
28012
+ return value;
28013
+ }
28014
+ try {
28015
+ return JSON.stringify(value ?? {});
28016
+ } catch {
28017
+ return String(value);
28018
+ }
28019
+ }
28020
+ function syntheticToolCallId(name, index) {
28021
+ const normalizedName = name.replace(/[^a-zA-Z0-9_-]/g, "_") || "tool";
28022
+ return `ollama_call_${normalizedName}_${index}`;
28023
+ }
28024
+ function normalizeToolCall(toolCall, index) {
28025
+ const name = toolCall.function?.name;
28026
+ if (typeof name !== "string" || name.length === 0) {
28027
+ return void 0;
28028
+ }
28029
+ return {
28030
+ id: typeof toolCall.id === "string" && toolCall.id.length > 0 ? toolCall.id : syntheticToolCallId(name, index),
28031
+ type: "function",
28032
+ function: {
28033
+ name,
28034
+ arguments: stringifyArguments(toolCall.function?.arguments)
28035
+ }
28036
+ };
28037
+ }
28038
+ function normalizeToolCalls(toolCalls, syntheticIdOffset = 0) {
28039
+ if (!Array.isArray(toolCalls)) {
28040
+ return [];
28041
+ }
28042
+ return toolCalls.flatMap((toolCall, index) => {
28043
+ const normalized = normalizeToolCall(toolCall, syntheticIdOffset + index);
28044
+ return normalized ? [normalized] : [];
28045
+ });
28046
+ }
28047
+ function countOllamaToolCalls(messages) {
28048
+ if (!Array.isArray(messages)) {
28049
+ return 0;
28050
+ }
28051
+ return messages.reduce(
28052
+ (count, message) => count + (isObject(message) && Array.isArray(message.tool_calls) ? message.tool_calls.length : 0),
28053
+ 0
28054
+ );
28055
+ }
28056
+ function imageBytes(value) {
28057
+ if (value instanceof Uint8Array) {
28058
+ return value;
28059
+ }
28060
+ if (value instanceof ArrayBuffer) {
28061
+ return new Uint8Array(value);
28062
+ }
28063
+ if (typeof value !== "string" || value.startsWith("data:")) {
28064
+ return void 0;
28065
+ }
28066
+ try {
28067
+ const decoded = atob(value.slice(0, 24));
28068
+ return Uint8Array.from(decoded, (character) => character.charCodeAt(0));
28069
+ } catch {
28070
+ return void 0;
28071
+ }
28072
+ }
28073
+ function inferImageMediaType(value) {
28074
+ if (typeof value === "string") {
28075
+ const dataUrlType = value.match(/^data:(image\/[^;]+);base64,/i)?.[1];
28076
+ if (dataUrlType) {
28077
+ return dataUrlType;
28078
+ }
28079
+ }
28080
+ const bytes = imageBytes(value);
28081
+ if (!bytes) {
28082
+ return void 0;
28083
+ }
28084
+ if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
28085
+ return "image/png";
28086
+ }
28087
+ if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
28088
+ return "image/jpeg";
28089
+ }
28090
+ const signature = String.fromCharCode(...bytes.slice(0, 12));
28091
+ if (signature.startsWith("GIF87a") || signature.startsWith("GIF89a")) {
28092
+ return "image/gif";
28093
+ }
28094
+ if (signature.startsWith("RIFF") && signature.slice(8, 12) === "WEBP") {
28095
+ return "image/webp";
28096
+ }
28097
+ return void 0;
28098
+ }
28099
+ function normalizeTextAndImages(content, images) {
28100
+ if (!images || images.length === 0) {
28101
+ return { content };
28102
+ }
28103
+ const imageParts = [];
28104
+ const unrecognizedImages = [];
28105
+ for (const image of images) {
28106
+ let localImagePath;
28107
+ let localPathMediaType;
28108
+ if (typeof image === "string" && !/^data:/i.test(image) && !/^https?:\/\//i.test(image)) {
28109
+ const extension = image.match(/\.([a-z0-9]+)$/i)?.[1]?.toLowerCase();
28110
+ const extensionMediaType = {
28111
+ png: "image/png",
28112
+ jpg: "image/jpeg",
28113
+ jpeg: "image/jpeg",
28114
+ gif: "image/gif",
28115
+ webp: "image/webp"
28116
+ }[extension ?? ""];
28117
+ if (extensionMediaType && isomorph_default.statSync) {
28118
+ try {
28119
+ if (isomorph_default.statSync(image).isFile()) {
28120
+ localImagePath = image;
28121
+ localPathMediaType = extensionMediaType;
28122
+ }
28123
+ } catch {
28124
+ }
28125
+ }
28126
+ }
28127
+ const mediaType = localPathMediaType ?? inferImageMediaType(image);
28128
+ if (!mediaType) {
28129
+ unrecognizedImages.push(image);
28130
+ continue;
28131
+ }
28132
+ const processedImage = localImagePath ? new Attachment({
28133
+ data: localImagePath,
28134
+ filename: localImagePath.split(/[\\/]/).at(-1) ?? "image",
28135
+ contentType: mediaType
28136
+ }) : processInputAttachments({
28137
+ type: "image",
28138
+ image,
28139
+ mediaType
28140
+ }).image;
28141
+ imageParts.push({
28142
+ type: "image_url",
28143
+ image_url: { url: processedImage }
28144
+ });
28145
+ }
28146
+ return {
28147
+ content: imageParts.length > 0 ? [...content ? [{ type: "text", text: content }] : [], ...imageParts] : content,
28148
+ ...unrecognizedImages.length > 0 ? { unrecognizedImages } : {}
28149
+ };
28150
+ }
28151
+ function normalizeMessage(message, toolCallId, syntheticToolCallIdOffset = 0) {
28152
+ if (typeof message.role !== "string") {
28153
+ return void 0;
28154
+ }
28155
+ const toolCalls = normalizeToolCalls(
28156
+ message.tool_calls,
28157
+ syntheticToolCallIdOffset
28158
+ );
28159
+ if (message.role === "tool") {
28160
+ const toolName = typeof message.tool_name === "string" && message.tool_name.length > 0 ? message.tool_name : "tool";
28161
+ return {
28162
+ role: "tool",
28163
+ tool_call_id: toolCallId ?? syntheticToolCallId(toolName, 0),
28164
+ content: typeof message.content === "string" ? message.content : ""
28165
+ };
28166
+ }
28167
+ const normalizedContent = normalizeTextAndImages(
28168
+ typeof message.content === "string" ? message.content || (toolCalls.length > 0 ? null : "") : toolCalls.length > 0 ? null : "",
28169
+ message.images
28170
+ );
28171
+ return {
28172
+ role: message.role,
28173
+ content: normalizedContent.content,
28174
+ ...typeof message.thinking === "string" && message.thinking.length > 0 ? { reasoning: message.thinking } : {},
28175
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {},
28176
+ ...normalizedContent.unrecognizedImages ? { images: normalizedContent.unrecognizedImages } : {}
28177
+ };
28178
+ }
28179
+ function normalizeMessages(messages) {
28180
+ if (!Array.isArray(messages)) {
28181
+ return [];
28182
+ }
28183
+ const pendingToolCallIds = /* @__PURE__ */ new Map();
28184
+ let syntheticToolCallIdOffset = 0;
28185
+ return messages.flatMap((message) => {
28186
+ if (!isObject(message)) {
28187
+ return [];
28188
+ }
28189
+ const ollamaMessage = message;
28190
+ let toolCallId;
28191
+ if (ollamaMessage.role === "tool") {
28192
+ const toolName = ollamaMessage.tool_name;
28193
+ if (typeof toolName === "string") {
28194
+ toolCallId = pendingToolCallIds.get(toolName)?.shift();
28195
+ }
28196
+ }
28197
+ const normalized = normalizeMessage(
28198
+ ollamaMessage,
28199
+ toolCallId,
28200
+ syntheticToolCallIdOffset
28201
+ );
28202
+ if (Array.isArray(ollamaMessage.tool_calls)) {
28203
+ syntheticToolCallIdOffset += ollamaMessage.tool_calls.length;
28204
+ }
28205
+ if (ollamaMessage.role === "assistant" && normalized) {
28206
+ const toolCalls = Array.isArray(normalized.tool_calls) ? normalized.tool_calls : [];
28207
+ for (const toolCall of toolCalls) {
28208
+ if (!isObject(toolCall) || !isObject(toolCall.function)) {
28209
+ continue;
28210
+ }
28211
+ const name = toolCall.function.name;
28212
+ const id = toolCall.id;
28213
+ if (typeof name === "string" && typeof id === "string") {
28214
+ const ids = pendingToolCallIds.get(name) ?? [];
28215
+ ids.push(id);
28216
+ pendingToolCallIds.set(name, ids);
28217
+ }
28218
+ }
28219
+ }
28220
+ return normalized ? [normalized] : [];
28221
+ });
28222
+ }
28223
+ function normalizeToolDefinition(tool) {
28224
+ const fn = tool.function;
28225
+ if (!fn || typeof fn.name !== "string" || fn.name.length === 0) {
28226
+ return void 0;
28227
+ }
28228
+ return {
28229
+ type: "function",
28230
+ function: {
28231
+ name: fn.name,
28232
+ ...typeof fn.description === "string" ? { description: fn.description } : {},
28233
+ ...isObject(fn.parameters) ? { parameters: fn.parameters } : {}
28234
+ }
28235
+ };
28236
+ }
28237
+ function extractToolsMetadata(tools) {
28238
+ if (!Array.isArray(tools)) {
28239
+ return {};
28240
+ }
28241
+ const normalized = tools.flatMap((tool) => {
28242
+ if (!isObject(tool)) {
28243
+ return [];
28244
+ }
28245
+ const definition = normalizeToolDefinition(tool);
28246
+ return definition ? [definition] : [];
28247
+ });
28248
+ return normalized.length > 0 ? { tools: normalized } : {};
28249
+ }
28250
+ function extractOptionsMetadata(options) {
28251
+ if (!isObject(options)) {
28252
+ return {};
28253
+ }
28254
+ const metadata = {};
28255
+ const mappings = [
28256
+ ["temperature", "temperature"],
28257
+ ["top_p", "top_p"],
28258
+ ["num_predict", "max_tokens"],
28259
+ ["frequency_penalty", "frequency_penalty"],
28260
+ ["presence_penalty", "presence_penalty"],
28261
+ ["stop", "stop"]
28262
+ ];
28263
+ for (const [source, target] of mappings) {
28264
+ if (options[source] !== void 0) {
28265
+ metadata[target] = options[source];
28266
+ }
28267
+ }
28268
+ return metadata;
28269
+ }
28270
+ function extractRequestMetadata(request) {
28271
+ return {
28272
+ provider: "ollama",
28273
+ ...typeof request?.model === "string" ? { model: request.model } : {},
28274
+ ...extractOptionsMetadata(request?.options),
28275
+ ...request?.format !== void 0 ? { response_format: request.format } : {}
28276
+ };
28277
+ }
28278
+ function extractOllamaChatInput([request]) {
28279
+ return {
28280
+ input: normalizeMessages(request.messages),
28281
+ metadata: {
28282
+ ...extractRequestMetadata(request),
28283
+ ...extractToolsMetadata(request.tools)
28284
+ }
28285
+ };
28286
+ }
28287
+ function extractOllamaGenerateInput([request]) {
28288
+ const normalizedPrompt = normalizeTextAndImages(
28289
+ typeof request.prompt === "string" ? request.prompt : "",
28290
+ Array.isArray(request.images) ? request.images : void 0
28291
+ );
28292
+ const input = [
28293
+ ...typeof request.system === "string" ? [{ role: "system", content: request.system }] : [],
28294
+ {
28295
+ role: "user",
28296
+ content: normalizedPrompt.content,
28297
+ ...typeof request.suffix === "string" ? { suffix: request.suffix } : {},
28298
+ ...normalizedPrompt.unrecognizedImages ? { images: normalizedPrompt.unrecognizedImages } : {}
28299
+ }
28300
+ ];
28301
+ return {
28302
+ input,
28303
+ metadata: extractRequestMetadata(request)
28304
+ };
28305
+ }
28306
+ function extractOllamaEmbedInput([request]) {
28307
+ return {
28308
+ input: request.input,
28309
+ metadata: extractRequestMetadata(request)
28310
+ };
28311
+ }
28312
+ function extractOllamaChatOutput(result, syntheticToolCallIdOffset = 0) {
28313
+ if (!isObject(result) || !isObject(result.message)) {
28314
+ return void 0;
28315
+ }
28316
+ const message = normalizeMessage(
28317
+ result.message,
28318
+ void 0,
28319
+ syntheticToolCallIdOffset
28320
+ );
28321
+ if (!message) {
28322
+ return void 0;
28323
+ }
28324
+ const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
28325
+ return [
28326
+ {
28327
+ index: 0,
28328
+ finish_reason: normalizeFinishReason(result, toolCalls.length > 0),
28329
+ message
28330
+ }
28331
+ ];
28332
+ }
28333
+ function extractOllamaGenerateOutput(result) {
28334
+ if (!isObject(result) || typeof result.response !== "string") {
28335
+ return void 0;
28336
+ }
28337
+ return [
28338
+ {
28339
+ index: 0,
28340
+ finish_reason: normalizeFinishReason(result),
28341
+ message: {
28342
+ role: "assistant",
28343
+ content: result.response,
28344
+ ...typeof result.thinking === "string" && result.thinking.length > 0 ? { reasoning: result.thinking } : {}
28345
+ }
28346
+ }
28347
+ ];
28348
+ }
28349
+ function extractOllamaEmbedOutput(result) {
28350
+ const embedding = Array.isArray(result?.embeddings) ? result.embeddings[0] : void 0;
28351
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
28352
+ }
28353
+ function extractOllamaResponseMetadata(result) {
28354
+ return typeof result?.model === "string" ? { model: result.model } : void 0;
28355
+ }
28356
+ function extractOllamaMetrics(result) {
28357
+ const metrics = {};
28358
+ const promptTokens = result?.prompt_eval_count;
28359
+ const completionTokens = result?.eval_count;
28360
+ if (isNonNegativeNumber(promptTokens)) {
28361
+ metrics.prompt_tokens = promptTokens;
28362
+ }
28363
+ if (isNonNegativeNumber(completionTokens)) {
28364
+ metrics.completion_tokens = completionTokens;
28365
+ }
28366
+ if (isNonNegativeNumber(promptTokens) || isNonNegativeNumber(completionTokens)) {
28367
+ metrics.tokens = (isNonNegativeNumber(promptTokens) ? promptTokens : 0) + (isNonNegativeNumber(completionTokens) ? completionTokens : 0);
28368
+ }
28369
+ return metrics;
28370
+ }
28371
+ function aggregateOllamaChatChunks(chunks, _result, event, _startTime) {
28372
+ const last = chunks.at(-1);
28373
+ const message = {
28374
+ role: "assistant",
28375
+ content: chunks.map((chunk) => chunk.message?.content ?? "").join(""),
28376
+ thinking: chunks.map((chunk) => chunk.message?.thinking ?? "").join(""),
28377
+ tool_calls: chunks.flatMap((chunk) => chunk.message?.tool_calls ?? [])
28378
+ };
28379
+ const response = {
28380
+ ...last,
28381
+ message
28382
+ };
28383
+ return {
28384
+ output: extractOllamaChatOutput(
28385
+ response,
28386
+ countOllamaToolCalls(event?.arguments?.[0]?.messages)
28387
+ ),
28388
+ metrics: extractOllamaMetrics(last ?? {}),
28389
+ metadata: extractOllamaResponseMetadata(last ?? {})
28390
+ };
28391
+ }
28392
+ function aggregateOllamaGenerateChunks(chunks, _result, _event, _startTime) {
28393
+ const last = chunks.at(-1);
28394
+ const response = {
28395
+ ...last,
28396
+ response: chunks.map((chunk) => chunk.response ?? "").join(""),
28397
+ thinking: chunks.map((chunk) => chunk.thinking ?? "").join("")
28398
+ };
28399
+ return {
28400
+ output: extractOllamaGenerateOutput(response),
28401
+ metrics: extractOllamaMetrics(last ?? {}),
28402
+ metadata: extractOllamaResponseMetadata(last ?? {})
28403
+ };
28404
+ }
28405
+
26733
28406
  // src/instrumentation/plugins/google-adk-plugin.ts
26734
28407
  var GoogleADKPlugin = class extends BasePlugin {
26735
28408
  activeRunnerSpans = /* @__PURE__ */ new Map();
@@ -29365,7 +31038,7 @@ function getStringProperty2(obj, key) {
29365
31038
  return typeof value === "string" ? value : void 0;
29366
31039
  }
29367
31040
  function extractMetricsFromUsage(usage) {
29368
- const metrics = {
31041
+ const rawMetrics = {
29369
31042
  prompt_tokens: usage.inputTokens,
29370
31043
  completion_tokens: usage.outputTokens,
29371
31044
  ...extractAnthropicCacheTokens(
@@ -29374,10 +31047,10 @@ function extractMetricsFromUsage(usage) {
29374
31047
  )
29375
31048
  };
29376
31049
  if (usage.reasoningTokens !== void 0) {
29377
- metrics.completion_reasoning_tokens = usage.reasoningTokens;
29378
- metrics.reasoning_tokens = usage.reasoningTokens;
31050
+ rawMetrics.completion_reasoning_tokens = usage.reasoningTokens;
31051
+ rawMetrics.reasoning_tokens = usage.reasoningTokens;
29379
31052
  }
29380
- Object.assign(metrics, finalizeAnthropicTokens(metrics));
31053
+ const metrics = finalizeAnthropicTokens(rawMetrics);
29381
31054
  const metadata = {
29382
31055
  model: usage.model
29383
31056
  };
@@ -30406,12 +32079,13 @@ function sanitizeLoggedValue(value, seen = /* @__PURE__ */ new WeakSet(), depth
30406
32079
  }
30407
32080
 
30408
32081
  // src/instrumentation/plugins/pi-coding-agent-plugin.ts
30409
- var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
32082
+ var piAgentPatchStates = /* @__PURE__ */ new WeakMap();
32083
+ var piAgentEventSubscriptions = /* @__PURE__ */ new WeakSet();
30410
32084
  var piPromptContextStore;
30411
32085
  var PiCodingAgentPlugin = class extends BasePlugin {
30412
32086
  activePromptStates = /* @__PURE__ */ new Set();
30413
32087
  onEnable() {
30414
- this.subscribeToPrompt();
32088
+ this.interceptPrompt();
30415
32089
  }
30416
32090
  onDisable() {
30417
32091
  for (const unsubscribe of this.unsubscribers) {
@@ -30419,65 +32093,74 @@ var PiCodingAgentPlugin = class extends BasePlugin {
30419
32093
  }
30420
32094
  this.unsubscribers = [];
30421
32095
  for (const state of [...this.activePromptStates]) {
30422
- void finalizePiPromptRun(state).catch((error) => {
30423
- logInstrumentationError4("Pi Coding Agent disable cleanup", error);
30424
- });
32096
+ finishPiPromptRun(state);
30425
32097
  }
30426
32098
  }
30427
- subscribeToPrompt() {
30428
- const channel = piCodingAgentChannels.prompt.tracingChannel();
30429
- const states = /* @__PURE__ */ new WeakMap();
30430
- const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel);
30431
- const handlers = {
30432
- start: (event) => {
30433
- const state = startPiPromptRun(event, (state2) => {
30434
- this.activePromptStates.delete(state2);
30435
- });
30436
- if (state) {
30437
- this.activePromptStates.add(state);
30438
- states.set(event, state);
30439
- }
30440
- },
30441
- asyncEnd: async (event) => {
30442
- const state = states.get(event);
30443
- if (!state) {
30444
- return;
30445
- }
30446
- states.delete(event);
30447
- state.promptCallEnded = true;
30448
- if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
30449
- if (!state.sawStreamFn) {
30450
- state.queued = true;
30451
- if (!state.streamPatchState.queuedPromptStates.includes(state)) {
30452
- state.streamPatchState.queuedPromptStates.push(state);
30453
- }
32099
+ interceptPrompt() {
32100
+ this.unsubscribers.push(
32101
+ piCodingAgentChannels.prompt.intercept(
32102
+ (target, thisArg, args, additional) => {
32103
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
32104
+ let state;
32105
+ try {
32106
+ state = startPiPromptRun(
32107
+ {
32108
+ ...additional,
32109
+ arguments: args,
32110
+ self: thisArg
32111
+ },
32112
+ (finalizedState) => {
32113
+ this.activePromptStates.delete(finalizedState);
32114
+ }
32115
+ );
32116
+ } catch (error) {
32117
+ logInstrumentationError4("Pi Coding Agent prompt start", error);
30454
32118
  }
30455
- return;
30456
- }
30457
- await finalizePiPromptRun(state);
30458
- },
30459
- error: async (event) => {
30460
- const state = states.get(event);
30461
- if (!state) {
30462
- return;
32119
+ if (!state) {
32120
+ return runWithAutoInstrumentationSuppressed(invokeTarget);
32121
+ }
32122
+ this.activePromptStates.add(state);
32123
+ return promptContextStore().run(
32124
+ state,
32125
+ () => runWithAutoInstrumentationSuppressed(() => {
32126
+ let result;
32127
+ try {
32128
+ result = invokeTarget();
32129
+ } catch (error) {
32130
+ finishPiPromptRun(state, error);
32131
+ throw error;
32132
+ }
32133
+ return Promise.resolve(result).then(
32134
+ (value) => {
32135
+ finishPiPromptCall(state);
32136
+ return value;
32137
+ },
32138
+ (error) => {
32139
+ finishPiPromptRun(state, error);
32140
+ throw error;
32141
+ }
32142
+ );
32143
+ })
32144
+ );
30463
32145
  }
30464
- states.delete(event);
30465
- await finalizePiPromptRun(state, event.error);
30466
- }
30467
- };
30468
- channel.subscribe(handlers);
30469
- this.unsubscribers.push(() => {
30470
- unbindAutoInstrumentationSuppression?.();
30471
- channel.unsubscribe(handlers);
30472
- });
32146
+ )
32147
+ );
30473
32148
  }
30474
32149
  };
32150
+ function finishPiPromptCall(state) {
32151
+ state.promptCallEnded = true;
32152
+ if (state.deferCompletionUntilTurnEnd && !state.turnEnded) {
32153
+ return;
32154
+ }
32155
+ finishPiPromptRun(state);
32156
+ }
30475
32157
  function startPiPromptRun(event, onFinalize) {
30476
32158
  const session = extractSession(event);
30477
32159
  const agent = session?.agent;
30478
32160
  if (!session || !isPiAgent(agent)) {
30479
32161
  return void 0;
30480
32162
  }
32163
+ installPiAgentInstrumentation(agent);
30481
32164
  const metadata = {
30482
32165
  ...extractSessionMetadata(session),
30483
32166
  ...extractPromptOptionsMetadata(event.arguments[1]),
@@ -30499,9 +32182,7 @@ function startPiPromptRun(event, onFinalize) {
30499
32182
  INSTRUMENTATION_NAMES.PI_CODING_AGENT
30500
32183
  )
30501
32184
  );
30502
- const streamPatchState = installPiStreamPatch(agent);
30503
32185
  const options = event.arguments[1];
30504
- const promptText = event.arguments[0];
30505
32186
  const state = {
30506
32187
  activeLlmSpans: /* @__PURE__ */ new Set(),
30507
32188
  activeToolSpans: /* @__PURE__ */ new Map(),
@@ -30513,29 +32194,10 @@ function startPiPromptRun(event, onFinalize) {
30513
32194
  metrics: {},
30514
32195
  onFinalize,
30515
32196
  promptCallEnded: false,
30516
- ...typeof promptText === "string" ? { promptText } : {},
30517
- queued: false,
30518
32197
  span,
30519
- sawStreamFn: false,
30520
32198
  startTime: getCurrentUnixTimestamp(),
30521
- streamPatchState,
30522
32199
  turnEnded: false
30523
32200
  };
30524
- state.restorePromptContext = enterPiPromptContext(state);
30525
- streamPatchState.activePromptStates.add(state);
30526
- try {
30527
- state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
30528
- try {
30529
- await runWithAutoInstrumentationSuppressed(
30530
- () => handlePiAgentEvent(state, agentEvent)
30531
- );
30532
- } catch (error) {
30533
- logInstrumentationError4("Pi Coding Agent event", error);
30534
- }
30535
- });
30536
- } catch (error) {
30537
- logInstrumentationError4("Pi Coding Agent event subscription", error);
30538
- }
30539
32201
  return state;
30540
32202
  }
30541
32203
  function extractSession(event) {
@@ -30549,111 +32211,55 @@ function promptContextStore() {
30549
32211
  piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
30550
32212
  return piPromptContextStore;
30551
32213
  }
30552
- function currentPromptContextFrames() {
30553
- return promptContextStore().getStore()?.frames ?? [];
30554
- }
30555
32214
  function currentPiPromptState() {
30556
- const frames = currentPromptContextFrames();
30557
- return frames[frames.length - 1]?.state;
30558
- }
30559
- function enterPiPromptContext(state) {
30560
- const frame = {
30561
- id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
30562
- state
30563
- };
30564
- promptContextStore().enterWith({
30565
- frames: [...currentPromptContextFrames(), frame]
30566
- });
30567
- return () => {
30568
- const frames = currentPromptContextFrames().filter(
30569
- (candidate) => candidate.id !== frame.id
30570
- );
30571
- promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
30572
- };
30573
- }
30574
- function installPiStreamPatch(agent) {
30575
- const existing = piStreamPatchStates.get(agent);
30576
- if (existing) {
30577
- if (agent.streamFn !== existing.wrappedStreamFn) {
30578
- debugLogger.debug(
30579
- "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
30580
- );
30581
- }
30582
- return existing;
30583
- }
30584
- const patchState = {
30585
- activePromptStates: /* @__PURE__ */ new Set(),
30586
- agent,
30587
- originalStreamFn: agent.streamFn,
30588
- queuedPromptStates: [],
30589
- wrappedStreamFn: agent.streamFn
30590
- };
30591
- patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
30592
- agent.streamFn = patchState.wrappedStreamFn;
30593
- piStreamPatchStates.set(agent, patchState);
30594
- return patchState;
30595
- }
30596
- function resolveStreamPromptState(patchState, context) {
30597
- let lastUserText;
30598
- if (Array.isArray(context.messages)) {
30599
- for (let i = context.messages.length - 1; i >= 0; i--) {
30600
- const message = context.messages[i];
30601
- if (isPiUserMessage(message)) {
30602
- if (typeof message.content === "string") {
30603
- lastUserText = message.content;
30604
- } else {
30605
- lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
30606
- }
30607
- break;
30608
- }
30609
- }
30610
- }
30611
- if (lastUserText !== void 0) {
30612
- const queuedMatch = patchState.queuedPromptStates.find(
30613
- (state) => state.promptText === lastUserText
30614
- );
30615
- if (queuedMatch) {
30616
- return queuedMatch;
30617
- }
30618
- const matches = [...patchState.activePromptStates].filter(
30619
- (state) => state.promptText === lastUserText
32215
+ return promptContextStore().getStore();
32216
+ }
32217
+ function installPiAgentInstrumentation(agent) {
32218
+ const existing = piAgentPatchStates.get(agent);
32219
+ if (!existing || agent.streamFn !== existing.wrappedStreamFn) {
32220
+ const patchState = {
32221
+ originalStreamFn: agent.streamFn,
32222
+ wrappedStreamFn: agent.streamFn
32223
+ };
32224
+ patchState.wrappedStreamFn = makeInstrumentedStreamFn(
32225
+ agent,
32226
+ patchState.originalStreamFn
30620
32227
  );
30621
- if (matches.length === 1) {
30622
- return matches[0];
30623
- }
32228
+ agent.streamFn = patchState.wrappedStreamFn;
32229
+ piAgentPatchStates.set(agent, patchState);
30624
32230
  }
30625
- const contextState = currentPiPromptState();
30626
- if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
30627
- return contextState;
32231
+ if (piAgentEventSubscriptions.has(agent)) {
32232
+ return;
30628
32233
  }
30629
- if (patchState.activePromptStates.size === 1) {
30630
- return [...patchState.activePromptStates][0];
32234
+ try {
32235
+ agent.subscribe(async (event) => {
32236
+ const state = currentPiPromptState();
32237
+ if (!state || state.agent !== agent || state.finalized) {
32238
+ return;
32239
+ }
32240
+ try {
32241
+ await runWithAutoInstrumentationSuppressed(
32242
+ () => handlePiAgentEvent(state, event)
32243
+ );
32244
+ } catch (error) {
32245
+ logInstrumentationError4("Pi Coding Agent event", error);
32246
+ }
32247
+ });
32248
+ piAgentEventSubscriptions.add(agent);
32249
+ } catch (error) {
32250
+ logInstrumentationError4("Pi Coding Agent event subscription", error);
30631
32251
  }
30632
- return void 0;
30633
32252
  }
30634
- function makeSharedInstrumentedStreamFn(patchState) {
32253
+ function makeInstrumentedStreamFn(agent, originalStreamFn) {
30635
32254
  return async function instrumentedPiStreamFn(model, context, options) {
30636
- const state = resolveStreamPromptState(patchState, context);
30637
- if (!state) {
30638
- const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
30639
- model,
30640
- context,
30641
- options
30642
- ]);
30643
- return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
32255
+ const invokeOriginal = () => Reflect.apply(originalStreamFn, this, [model, context, options]);
32256
+ const state = currentPiPromptState();
32257
+ if (!state || state.agent !== agent || state.finalized) {
32258
+ return invokeOriginal();
30644
32259
  }
30645
- state.sawStreamFn = true;
30646
- removeQueuedPromptState(state);
30647
- state.streamPatchState.eventPromptState = state;
30648
32260
  const llmState = await startPiLlmSpan(state, model, context, options);
30649
32261
  try {
30650
- const stream = await runWithAutoInstrumentationSuppressed(
30651
- () => Reflect.apply(patchState.originalStreamFn, this, [
30652
- model,
30653
- context,
30654
- options
30655
- ])
30656
- );
32262
+ const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
30657
32263
  return patchAssistantMessageStream(stream, state, llmState);
30658
32264
  } catch (error) {
30659
32265
  finishPiLlmSpan(state, llmState, void 0, error);
@@ -30800,13 +32406,6 @@ async function handlePiAgentEvent(state, event) {
30800
32406
  if (state.finalized) {
30801
32407
  return;
30802
32408
  }
30803
- const eventPromptState = state.streamPatchState.eventPromptState;
30804
- if (eventPromptState && eventPromptState !== state) {
30805
- return;
30806
- }
30807
- if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
30808
- return;
30809
- }
30810
32409
  switch (event.type) {
30811
32410
  case "message_end":
30812
32411
  if (isPiAssistantMessage(event.message)) {
@@ -30821,11 +32420,8 @@ async function handlePiAgentEvent(state, event) {
30821
32420
  addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
30822
32421
  }
30823
32422
  }
30824
- if (state.streamPatchState.eventPromptState === state) {
30825
- state.streamPatchState.eventPromptState = void 0;
30826
- }
30827
32423
  if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
30828
- await finalizePiPromptRun(state);
32424
+ finishPiPromptRun(state);
30829
32425
  }
30830
32426
  return;
30831
32427
  case "tool_execution_start":
@@ -30898,19 +32494,13 @@ function finishPiToolSpan(state, event) {
30898
32494
  }
30899
32495
  }
30900
32496
  }
30901
- async function finalizePiPromptRun(state, error) {
32497
+ function finishPiPromptRun(state, error) {
30902
32498
  if (state.finalized) {
30903
32499
  return;
30904
32500
  }
30905
32501
  state.finalized = true;
30906
32502
  state.onFinalize?.(state);
30907
- restorePiStreamFn(state);
30908
- try {
30909
- state.unsubscribeAgent?.();
30910
- } catch (unsubscribeError) {
30911
- logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
30912
- }
30913
- await finishOpenLlmSpans(state, error);
32503
+ finishOpenLlmSpans(state, error);
30914
32504
  finishOpenToolSpans(state, error);
30915
32505
  const metadata = {
30916
32506
  ...state.metadata,
@@ -30927,34 +32517,14 @@ async function finalizePiPromptRun(state, error) {
30927
32517
  output: state.output
30928
32518
  });
30929
32519
  } finally {
30930
- state.span.end();
30931
- }
30932
- }
30933
- function restorePiStreamFn(state) {
30934
- const patchState = state.streamPatchState;
30935
- patchState.activePromptStates.delete(state);
30936
- removeQueuedPromptState(state);
30937
- if (patchState.eventPromptState === state) {
30938
- patchState.eventPromptState = void 0;
30939
- }
30940
- state.restorePromptContext?.();
30941
- if (patchState.activePromptStates.size > 0) {
30942
- return;
30943
- }
30944
- if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
30945
- patchState.agent.streamFn = patchState.originalStreamFn;
30946
- }
30947
- piStreamPatchStates.delete(patchState.agent);
30948
- }
30949
- function removeQueuedPromptState(state) {
30950
- state.queued = false;
30951
- const queuedPromptStates = state.streamPatchState.queuedPromptStates;
30952
- const index = queuedPromptStates.indexOf(state);
30953
- if (index >= 0) {
30954
- queuedPromptStates.splice(index, 1);
32520
+ try {
32521
+ state.span.end();
32522
+ } catch (endError) {
32523
+ logInstrumentationError4("Pi Coding Agent prompt end", endError);
32524
+ }
30955
32525
  }
30956
32526
  }
30957
- async function finishOpenLlmSpans(state, error) {
32527
+ function finishOpenLlmSpans(state, error) {
30958
32528
  for (const llmState of [...state.activeLlmSpans]) {
30959
32529
  finishPiLlmSpan(state, llmState, void 0, error);
30960
32530
  }
@@ -31035,7 +32605,7 @@ function normalizeAssistantMessage(message) {
31035
32605
  (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
31036
32606
  ).join("");
31037
32607
  const toolCalls = message.content.flatMap(
31038
- (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
32608
+ (part) => part.type === "toolCall" ? [normalizeToolCall2(part)] : []
31039
32609
  );
31040
32610
  return {
31041
32611
  role: "assistant",
@@ -31070,13 +32640,13 @@ function normalizeUserContent(content) {
31070
32640
  return part;
31071
32641
  });
31072
32642
  }
31073
- function normalizeToolCall(toolCall) {
32643
+ function normalizeToolCall2(toolCall) {
31074
32644
  return {
31075
32645
  id: toolCall.id,
31076
32646
  type: "function",
31077
32647
  function: {
31078
32648
  name: toolCall.name,
31079
- arguments: stringifyArguments(toolCall.arguments)
32649
+ arguments: stringifyArguments2(toolCall.arguments)
31080
32650
  }
31081
32651
  };
31082
32652
  }
@@ -31259,7 +32829,7 @@ function cleanMetrics5(metrics) {
31259
32829
  }
31260
32830
  return cleaned;
31261
32831
  }
31262
- function stringifyArguments(value) {
32832
+ function stringifyArguments2(value) {
31263
32833
  if (typeof value === "string") {
31264
32834
  return value;
31265
32835
  }
@@ -31435,8 +33005,7 @@ function startAgentStream(event, activeChildParents) {
31435
33005
  ...extractAgentMetadata2(agent),
31436
33006
  ...extractModelMetadata3(model),
31437
33007
  "strands.operation": "Agent.stream",
31438
- provider: extractProvider(model),
31439
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
33008
+ provider: extractProvider(model)
31440
33009
  };
31441
33010
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
31442
33011
  const attachmentCache = createStrandsAttachmentCache();
@@ -31486,8 +33055,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
31486
33055
  const metadata = {
31487
33056
  "strands.operation": operation,
31488
33057
  provider: "strands",
31489
- ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {},
31490
- ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
33058
+ ...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
31491
33059
  };
31492
33060
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
31493
33061
  const input = processStrandsInputAttachments(event.arguments[0]);
@@ -32273,6 +33841,296 @@ function logInstrumentationError5(context, error) {
32273
33841
  debugLogger.debug(`${context}:`, error);
32274
33842
  }
32275
33843
 
33844
+ // src/instrumentation/plugins/voyageai-plugin.ts
33845
+ var RERANK_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
33846
+ "model",
33847
+ "returnDocuments",
33848
+ "topK",
33849
+ "truncation"
33850
+ ]);
33851
+ var VoyageAIPlugin = class extends BasePlugin {
33852
+ onEnable() {
33853
+ this.unsubscribers.push(
33854
+ interceptVoyageAICall(
33855
+ voyageAIChannels.embed,
33856
+ "voyageai.embed",
33857
+ extractTextEmbeddingInput,
33858
+ summarizeEmbeddingOutput,
33859
+ extractEmbeddingUsageMetrics
33860
+ ),
33861
+ interceptVoyageAICall(
33862
+ voyageAIChannels.multimodalEmbed,
33863
+ "voyageai.multimodalEmbed",
33864
+ extractMultimodalEmbeddingInput,
33865
+ summarizeEmbeddingOutput,
33866
+ extractEmbeddingUsageMetrics
33867
+ ),
33868
+ interceptVoyageAICall(
33869
+ voyageAIChannels.rerank,
33870
+ "voyageai.rerank",
33871
+ extractRerankInput,
33872
+ summarizeRerankOutput
33873
+ ),
33874
+ interceptVoyageAICall(
33875
+ voyageAIChannels.contextualizedEmbed,
33876
+ "voyageai.contextualizedEmbed",
33877
+ extractContextualizedEmbeddingInput,
33878
+ summarizeContextualizedEmbeddingOutput,
33879
+ extractEmbeddingUsageMetrics
33880
+ )
33881
+ );
33882
+ }
33883
+ onDisable() {
33884
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
33885
+ }
33886
+ };
33887
+ function interceptVoyageAICall(channel, name, extractInput2, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
33888
+ return channel.intercept((target, thisArg, args) => {
33889
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
33890
+ if (isAutoInstrumentationSuppressed()) {
33891
+ return invokeTarget();
33892
+ }
33893
+ let span;
33894
+ try {
33895
+ const { input, metadata } = extractInput2(args);
33896
+ span = startSpan(
33897
+ withSpanInstrumentationName(
33898
+ {
33899
+ event: { input, metadata },
33900
+ name,
33901
+ spanAttributes: { type: "llm" /* LLM */ }
33902
+ },
33903
+ INSTRUMENTATION_NAMES.VOYAGEAI
33904
+ )
33905
+ );
33906
+ } catch (error) {
33907
+ debugLogger.error(`Error starting span for ${name}:`, error);
33908
+ return invokeTarget();
33909
+ }
33910
+ let result;
33911
+ try {
33912
+ result = withCurrent(
33913
+ span,
33914
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
33915
+ );
33916
+ } catch (error) {
33917
+ finishVoyageAISpan(span, name, () => span.log({ error }));
33918
+ throw error;
33919
+ }
33920
+ void Promise.resolve(result).then(
33921
+ (value) => finishVoyageAISpan(span, name, () => {
33922
+ const metadata = extractResponseMetadata3(value);
33923
+ span.log({
33924
+ output: extractOutput2(value),
33925
+ ...metadata ? { metadata } : {},
33926
+ metrics: extractMetrics2(value)
33927
+ });
33928
+ }),
33929
+ (error) => finishVoyageAISpan(span, name, () => span.log({ error }))
33930
+ );
33931
+ return result;
33932
+ });
33933
+ }
33934
+ function finishVoyageAISpan(span, name, log2) {
33935
+ try {
33936
+ log2();
33937
+ } catch (error) {
33938
+ debugLogger.error(`Error logging span for ${name}:`, error);
33939
+ }
33940
+ try {
33941
+ span.end();
33942
+ } catch (error) {
33943
+ debugLogger.error(`Error ending span for ${name}:`, error);
33944
+ }
33945
+ }
33946
+ function getRequestArg2(args) {
33947
+ if (Array.isArray(args)) {
33948
+ return isObject(args[0]) ? args[0] : void 0;
33949
+ }
33950
+ if (!isObject(args)) {
33951
+ return void 0;
33952
+ }
33953
+ const firstArg = Reflect.get(args, "0");
33954
+ return isObject(firstArg) ? firstArg : void 0;
33955
+ }
33956
+ function pickMetadata(request, allowlist) {
33957
+ const metadata = {};
33958
+ if (request) {
33959
+ for (const key of allowlist) {
33960
+ if (!Object.hasOwn(request, key)) {
33961
+ continue;
33962
+ }
33963
+ const value = request[key];
33964
+ if (value !== void 0) {
33965
+ metadata[key] = value;
33966
+ }
33967
+ }
33968
+ }
33969
+ return {
33970
+ ...metadata,
33971
+ provider: "voyage"
33972
+ };
33973
+ }
33974
+ function buildEmbeddingInput(inputs, request) {
33975
+ const outputDimensions = request?.outputDimension;
33976
+ return {
33977
+ inputs,
33978
+ ...typeof outputDimensions === "number" && Number.isFinite(outputDimensions) ? { output_dimensions: outputDimensions } : {}
33979
+ };
33980
+ }
33981
+ function embeddingMetadata(request) {
33982
+ return {
33983
+ ...typeof request?.model === "string" ? { model: request.model } : {},
33984
+ provider: "voyage"
33985
+ };
33986
+ }
33987
+ function extractTextEmbeddingInput(args) {
33988
+ const request = getRequestArg2(args);
33989
+ const rawInput = request?.input;
33990
+ const values = Array.isArray(rawInput) ? rawInput : [rawInput];
33991
+ return {
33992
+ input: buildEmbeddingInput(
33993
+ values.flatMap(
33994
+ (value) => typeof value === "string" ? [{ content: value }] : []
33995
+ ),
33996
+ request
33997
+ ),
33998
+ metadata: embeddingMetadata(request)
33999
+ };
34000
+ }
34001
+ function extractContextualizedEmbeddingInput(args) {
34002
+ const request = getRequestArg2(args);
34003
+ const rawInputs = request?.inputs;
34004
+ const values = Array.isArray(rawInputs) ? rawInputs.flatMap((value) => Array.isArray(value) ? value : [value]) : [];
34005
+ return {
34006
+ input: buildEmbeddingInput(
34007
+ values.flatMap(
34008
+ (value) => typeof value === "string" ? [{ content: value }] : []
34009
+ ),
34010
+ request
34011
+ ),
34012
+ metadata: embeddingMetadata(request)
34013
+ };
34014
+ }
34015
+ function extractMultimodalEmbeddingInput(args) {
34016
+ const request = getRequestArg2(args);
34017
+ const rawInputs = request?.inputs;
34018
+ const inputs = Array.isArray(rawInputs) ? rawInputs.map((rawInput) => {
34019
+ const rawContent = isObject(rawInput) ? rawInput.content : void 0;
34020
+ return {
34021
+ content: Array.isArray(rawContent) ? rawContent.flatMap(normalizeMultimodalContentPart) : []
34022
+ };
34023
+ }) : [];
34024
+ const input = buildEmbeddingInput(inputs, request);
34025
+ const processedInput = processInputAttachments(input);
34026
+ return {
34027
+ input: hasInlineEmbeddingMedia(processedInput) ? input : processedInput,
34028
+ metadata: embeddingMetadata(request)
34029
+ };
34030
+ }
34031
+ function normalizeMultimodalContentPart(part) {
34032
+ if (!isObject(part) || typeof part.type !== "string") {
34033
+ return [];
34034
+ }
34035
+ if (part.type === "text") {
34036
+ return typeof part.text === "string" ? [{ type: "text", text: part.text }] : [];
34037
+ }
34038
+ const camelCaseField = {
34039
+ image_base64: "imageBase64",
34040
+ image_url: "imageUrl",
34041
+ video_base64: "videoBase64",
34042
+ video_url: "videoUrl"
34043
+ };
34044
+ const field = camelCaseField[part.type];
34045
+ if (!field) {
34046
+ return [];
34047
+ }
34048
+ const data = typeof part[field] === "string" ? part[field] : part[part.type];
34049
+ if (typeof data !== "string") {
34050
+ return [];
34051
+ }
34052
+ return part.type.startsWith("image_") ? [{ type: "image_url", image_url: { url: data } }] : [{ type: "file", file: { file_data: data } }];
34053
+ }
34054
+ function hasInlineEmbeddingMedia(input) {
34055
+ return input.inputs.some(
34056
+ ({ content }) => Array.isArray(content) ? content.some((part) => {
34057
+ const value = part.type === "image_url" ? part.image_url.url : part.type === "file" ? part.file.file_data : void 0;
34058
+ return typeof value === "string" && value.startsWith("data:");
34059
+ }) : false
34060
+ );
34061
+ }
34062
+ function extractRerankInput(args) {
34063
+ const request = getRequestArg2(args);
34064
+ const documents = request?.documents;
34065
+ return {
34066
+ input: {
34067
+ documents,
34068
+ query: request?.query
34069
+ },
34070
+ metadata: {
34071
+ ...pickMetadata(request, RERANK_METADATA_ALLOWLIST),
34072
+ ...Array.isArray(documents) ? { document_count: documents.length } : {}
34073
+ }
34074
+ };
34075
+ }
34076
+ function extractResponseMetadata3(result) {
34077
+ if (!isObject(result)) {
34078
+ return void 0;
34079
+ }
34080
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
34081
+ const model = typeof result.model === "string" ? result.model : typeof rawResponse?.model === "string" ? rawResponse.model : void 0;
34082
+ return model ? { model } : void 0;
34083
+ }
34084
+ function summarizeEmbeddingOutput(result) {
34085
+ return {
34086
+ count: isObject(result) && Array.isArray(result.data) ? result.data.length : 0
34087
+ };
34088
+ }
34089
+ function summarizeRerankOutput(result) {
34090
+ if (!isObject(result) || !Array.isArray(result.data)) {
34091
+ return void 0;
34092
+ }
34093
+ return result.data.slice(0, 100).map((item) => ({
34094
+ index: isObject(item) ? item.index : void 0,
34095
+ relevance_score: isObject(item) ? (typeof item.relevanceScore === "number" ? item.relevanceScore : item.relevance_score) ?? null : null
34096
+ }));
34097
+ }
34098
+ function summarizeContextualizedEmbeddingOutput(result) {
34099
+ if (!isObject(result)) {
34100
+ return { count: 0 };
34101
+ }
34102
+ if (Array.isArray(result.results)) {
34103
+ return {
34104
+ count: result.results.reduce(
34105
+ (count, item) => count + (isObject(item) && Array.isArray(item.embeddings) ? item.embeddings.length : 0),
34106
+ 0
34107
+ )
34108
+ };
34109
+ }
34110
+ if (!Array.isArray(result.data)) {
34111
+ return { count: 0 };
34112
+ }
34113
+ return {
34114
+ count: result.data.reduce(
34115
+ (count, item) => count + (isObject(item) && Array.isArray(item.data) ? item.data.length : 0),
34116
+ 0
34117
+ )
34118
+ };
34119
+ }
34120
+ function extractEmbeddingUsageMetrics(result) {
34121
+ const metrics = extractUsageMetrics3(result);
34122
+ return typeof metrics.tokens === "number" ? { prompt_tokens: metrics.tokens, tokens: metrics.tokens } : {};
34123
+ }
34124
+ function extractUsageMetrics3(result) {
34125
+ if (!isObject(result)) {
34126
+ return {};
34127
+ }
34128
+ const rawResponse = isObject(result.rawResponse) ? result.rawResponse : void 0;
34129
+ const usage = isObject(result.usage) ? result.usage : isObject(rawResponse?.usage) ? rawResponse.usage : void 0;
34130
+ const tokens = typeof result.totalTokens === "number" ? result.totalTokens : usage?.totalTokens ?? usage?.total_tokens;
34131
+ return typeof tokens === "number" && Number.isFinite(tokens) && tokens >= 0 ? { tokens } : {};
34132
+ }
34133
+
32276
34134
  // src/instrumentation/plugins/cloudflare-ai-chat-instrumentation.ts
32277
34135
  var wrappedTurnRunners = /* @__PURE__ */ new WeakSet();
32278
34136
  var wrappedResponseHooks = /* @__PURE__ */ new WeakSet();
@@ -32802,6 +34660,7 @@ var BraintrustPlugin = class extends BasePlugin {
32802
34660
  anthropicPlugin = null;
32803
34661
  aiSDKPlugin = null;
32804
34662
  claudeAgentSDKPlugin = null;
34663
+ cloudflareThinkPlugin = null;
32805
34664
  cursorSDKPlugin = null;
32806
34665
  openAIAgentsPlugin = null;
32807
34666
  googleGenAIPlugin = null;
@@ -32810,6 +34669,7 @@ var BraintrustPlugin = class extends BasePlugin {
32810
34669
  openRouterPlugin = null;
32811
34670
  openRouterAgentPlugin = null;
32812
34671
  mistralPlugin = null;
34672
+ ollamaPlugin = null;
32813
34673
  googleADKPlugin = null;
32814
34674
  coherePlugin = null;
32815
34675
  groqPlugin = null;
@@ -32821,6 +34681,7 @@ var BraintrustPlugin = class extends BasePlugin {
32821
34681
  langSmithPlugin = null;
32822
34682
  piCodingAgentPlugin = null;
32823
34683
  strandsAgentSDKPlugin = null;
34684
+ voyageAIPlugin = null;
32824
34685
  cloudflareAIChatPlugin = null;
32825
34686
  cloudflareAgentsPlugin = null;
32826
34687
  constructor(config = {}) {
@@ -32849,6 +34710,10 @@ var BraintrustPlugin = class extends BasePlugin {
32849
34710
  this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
32850
34711
  this.claudeAgentSDKPlugin.enable();
32851
34712
  }
34713
+ if (integrations.cloudflareThink !== false) {
34714
+ this.cloudflareThinkPlugin = new CloudflareThinkPlugin();
34715
+ this.cloudflareThinkPlugin.enable();
34716
+ }
32852
34717
  if (integrations.cursorSDK !== false && integrations.cursor !== false) {
32853
34718
  this.cursorSDKPlugin = new CursorSDKPlugin();
32854
34719
  this.cursorSDKPlugin.enable();
@@ -32879,6 +34744,10 @@ var BraintrustPlugin = class extends BasePlugin {
32879
34744
  this.mistralPlugin = new MistralPlugin();
32880
34745
  this.mistralPlugin.enable();
32881
34746
  }
34747
+ if (integrations.ollama !== false) {
34748
+ this.ollamaPlugin = new OllamaPlugin();
34749
+ this.ollamaPlugin.enable();
34750
+ }
32882
34751
  if (integrations.googleADK !== false) {
32883
34752
  this.googleADKPlugin = new GoogleADKPlugin();
32884
34753
  this.googleADKPlugin.enable();
@@ -32887,6 +34756,10 @@ var BraintrustPlugin = class extends BasePlugin {
32887
34756
  this.coherePlugin = new CoherePlugin();
32888
34757
  this.coherePlugin.enable();
32889
34758
  }
34759
+ if (integrations.voyageai !== false) {
34760
+ this.voyageAIPlugin = new VoyageAIPlugin();
34761
+ this.voyageAIPlugin.enable();
34762
+ }
32890
34763
  if (integrations.groq !== false) {
32891
34764
  this.groqPlugin = new GroqPlugin();
32892
34765
  this.groqPlugin.enable();
@@ -32955,6 +34828,10 @@ var BraintrustPlugin = class extends BasePlugin {
32955
34828
  this.claudeAgentSDKPlugin.disable();
32956
34829
  this.claudeAgentSDKPlugin = null;
32957
34830
  }
34831
+ if (this.cloudflareThinkPlugin) {
34832
+ this.cloudflareThinkPlugin.disable();
34833
+ this.cloudflareThinkPlugin = null;
34834
+ }
32958
34835
  if (this.cursorSDKPlugin) {
32959
34836
  this.cursorSDKPlugin.disable();
32960
34837
  this.cursorSDKPlugin = null;
@@ -32987,6 +34864,10 @@ var BraintrustPlugin = class extends BasePlugin {
32987
34864
  this.mistralPlugin.disable();
32988
34865
  this.mistralPlugin = null;
32989
34866
  }
34867
+ if (this.ollamaPlugin) {
34868
+ this.ollamaPlugin.disable();
34869
+ this.ollamaPlugin = null;
34870
+ }
32990
34871
  if (this.googleADKPlugin) {
32991
34872
  this.googleADKPlugin.disable();
32992
34873
  this.googleADKPlugin = null;
@@ -32995,6 +34876,10 @@ var BraintrustPlugin = class extends BasePlugin {
32995
34876
  this.coherePlugin.disable();
32996
34877
  this.coherePlugin = null;
32997
34878
  }
34879
+ if (this.voyageAIPlugin) {
34880
+ this.voyageAIPlugin.disable();
34881
+ this.voyageAIPlugin = null;
34882
+ }
32998
34883
  if (this.groqPlugin) {
32999
34884
  this.groqPlugin.disable();
33000
34885
  this.groqPlugin = null;
@@ -33361,7 +35246,7 @@ function wrapMastraAgent(agent, _options) {
33361
35246
 
33362
35247
  // src/node/config.ts
33363
35248
  import { AsyncLocalStorage } from "node:async_hooks";
33364
- import * as path from "node:path";
35249
+ import * as path2 from "node:path";
33365
35250
  import * as fs from "node:fs/promises";
33366
35251
  import * as os from "node:os";
33367
35252
  import * as fsSync from "node:fs";
@@ -33370,34 +35255,93 @@ import { promisify } from "node:util";
33370
35255
  import * as zlib from "node:zlib";
33371
35256
  import * as dotenv from "dotenv";
33372
35257
 
33373
- // src/gitutil.ts
33374
- import { simpleGit } from "simple-git";
33375
- var COMMON_BASE_BRANCHES = ["main", "master", "develop"];
33376
- async function currentRepo() {
33377
- try {
33378
- const git = simpleGit();
33379
- if (await git.checkIsRepo()) {
33380
- return git;
33381
- } else {
33382
- return null;
35258
+ // src/git-command.ts
35259
+ import { execFile } from "node:child_process";
35260
+ import { constants } from "node:fs";
35261
+ import { access } from "node:fs/promises";
35262
+ import * as path from "node:path";
35263
+ var GIT_EXECUTABLE_NAMES = process.platform === "win32" ? ["git.exe", "git"] : ["git"];
35264
+ var GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
35265
+ var gitExecutablePromise;
35266
+ function executableSearchPath() {
35267
+ return Object.entries(process.env).find(
35268
+ ([name]) => name.toUpperCase() === "PATH"
35269
+ )?.[1];
35270
+ }
35271
+ async function findGitExecutable(searchPath = executableSearchPath()) {
35272
+ if (!searchPath) {
35273
+ return void 0;
35274
+ }
35275
+ for (const rawSearchDir of searchPath.split(path.delimiter)) {
35276
+ const searchDir = rawSearchDir.trim().replace(/^"(.*)"$/, "$1");
35277
+ if (!path.isAbsolute(searchDir)) {
35278
+ continue;
35279
+ }
35280
+ for (const executableName of GIT_EXECUTABLE_NAMES) {
35281
+ const candidate = path.join(searchDir, executableName);
35282
+ try {
35283
+ await access(
35284
+ candidate,
35285
+ process.platform === "win32" ? constants.F_OK : constants.X_OK
35286
+ );
35287
+ return candidate;
35288
+ } catch {
35289
+ }
33383
35290
  }
33384
- } catch {
33385
- return null;
33386
35291
  }
35292
+ return void 0;
35293
+ }
35294
+ async function resolveGitExecutable() {
35295
+ gitExecutablePromise ??= findGitExecutable();
35296
+ return await gitExecutablePromise;
33387
35297
  }
35298
+ async function runGitCommand(args, options = {}) {
35299
+ const executable = await resolveGitExecutable();
35300
+ if (!executable) {
35301
+ throw new Error("Could not find a git executable on PATH");
35302
+ }
35303
+ return await new Promise((resolve, reject) => {
35304
+ execFile(
35305
+ executable,
35306
+ args,
35307
+ {
35308
+ cwd: options.cwd,
35309
+ encoding: "utf8",
35310
+ maxBuffer: GIT_MAX_BUFFER_BYTES
35311
+ },
35312
+ (error, stdout) => {
35313
+ if (error) {
35314
+ reject(error);
35315
+ } else {
35316
+ resolve(stdout);
35317
+ }
35318
+ }
35319
+ );
35320
+ });
35321
+ }
35322
+
35323
+ // src/gitutil.ts
35324
+ var COMMON_BASE_BRANCHES = ["main", "master", "develop"];
33388
35325
  var _baseBranch = null;
33389
35326
  async function getBaseBranch(remote = void 0) {
33390
35327
  if (_baseBranch === null) {
33391
- const git = await currentRepo();
33392
- if (git === null) {
35328
+ const repoPath = await currentRepoPath();
35329
+ if (!repoPath) {
33393
35330
  throw new Error("Not in a git repo");
33394
35331
  }
33395
- const remoteName = remote ?? (await git.getRemotes())[0]?.name;
35332
+ const runGit = async (args) => await runGitCommand(args, { cwd: repoPath });
35333
+ const remoteName = remote ?? (await runGit(["remote"])).trim().split(/\r?\n/)[0];
33396
35334
  if (!remoteName) {
33397
35335
  throw new Error("No remote found");
33398
35336
  }
33399
35337
  let branch = null;
33400
- const repoBranches = new Set((await git.branchLocal()).all);
35338
+ const repoBranches = new Set(
35339
+ (await runGit([
35340
+ "for-each-ref",
35341
+ "--format=%(refname:short)",
35342
+ "refs/heads/"
35343
+ ])).trim().split(/\r?\n/)
35344
+ );
33401
35345
  const matchingBaseBranches = COMMON_BASE_BRANCHES.filter(
33402
35346
  (b) => repoBranches.has(b)
33403
35347
  );
@@ -33405,7 +35349,7 @@ async function getBaseBranch(remote = void 0) {
33405
35349
  branch = matchingBaseBranches[0];
33406
35350
  } else {
33407
35351
  try {
33408
- const remoteInfo = await git.remote(["show", remoteName]);
35352
+ const remoteInfo = await runGit(["remote", "show", remoteName]);
33409
35353
  if (!remoteInfo) {
33410
35354
  throw new Error(`Could not find remote ${remoteName}`);
33411
35355
  }
@@ -33423,27 +35367,28 @@ async function getBaseBranch(remote = void 0) {
33423
35367
  return _baseBranch;
33424
35368
  }
33425
35369
  async function getBaseBranchAncestor(remote = void 0) {
33426
- const git = await currentRepo();
33427
- if (git === null) {
35370
+ const repoPath = await currentRepoPath();
35371
+ if (!repoPath) {
33428
35372
  throw new Error("Not in a git repo");
33429
35373
  }
33430
35374
  const { remote: remoteName, branch: baseBranch } = await getBaseBranch(remote);
33431
- const isDirty = (await git.diffSummary()).files.length > 0;
35375
+ const isDirty = (await runGitCommand(["diff", "--name-only"], {
35376
+ cwd: repoPath
35377
+ })).trim().length > 0;
33432
35378
  const head = isDirty ? "HEAD" : "HEAD^";
33433
35379
  try {
33434
- const ancestor = await git.raw([
33435
- "merge-base",
33436
- head,
33437
- `${remoteName}/${baseBranch}`
33438
- ]);
35380
+ const ancestor = await runGitCommand(
35381
+ ["merge-base", head, `${remoteName}/${baseBranch}`],
35382
+ { cwd: repoPath }
35383
+ );
33439
35384
  return ancestor.trim();
33440
35385
  } catch {
33441
35386
  return void 0;
33442
35387
  }
33443
35388
  }
33444
35389
  async function getPastNAncestors(n = 1e3, remote = void 0) {
33445
- const git = await currentRepo();
33446
- if (git === null) {
35390
+ const repoPath = await currentRepoPath();
35391
+ if (!repoPath) {
33447
35392
  return [];
33448
35393
  }
33449
35394
  let ancestor = void 0;
@@ -33458,8 +35403,10 @@ async function getPastNAncestors(n = 1e3, remote = void 0) {
33458
35403
  if (!ancestor) {
33459
35404
  return [];
33460
35405
  }
33461
- const commits = await git.log({ from: ancestor, to: "HEAD", maxCount: n });
33462
- return commits.all.slice(0, n).map((c) => c.hash);
35406
+ const commits = (await runGitCommand(["rev-list", `--max-count=${n}`, `${ancestor}..HEAD`], {
35407
+ cwd: repoPath
35408
+ })).trim();
35409
+ return commits ? commits.split(/\r?\n/).slice(0, n) : [];
33463
35410
  }
33464
35411
  async function attempt(fn) {
33465
35412
  try {
@@ -33490,9 +35437,14 @@ async function getRepoInfo(settings) {
33490
35437
  });
33491
35438
  return sanitized;
33492
35439
  }
35440
+ async function currentRepoPath() {
35441
+ return await attempt(
35442
+ async () => (await runGitCommand(["rev-parse", "--show-toplevel"])).trim()
35443
+ );
35444
+ }
33493
35445
  async function repoInfo() {
33494
- const git = await currentRepo();
33495
- if (git === null) {
35446
+ const repoPath = await currentRepoPath();
35447
+ if (!repoPath) {
33496
35448
  return void 0;
33497
35449
  }
33498
35450
  let commit = void 0;
@@ -33503,29 +35455,32 @@ async function repoInfo() {
33503
35455
  let tag = void 0;
33504
35456
  let branch = void 0;
33505
35457
  let git_diff = void 0;
33506
- const dirty = (await git.diffSummary()).files.length > 0;
33507
- commit = await attempt(async () => await git.revparse(["HEAD"]));
35458
+ const runGit = async (args) => await runGitCommand(args, { cwd: repoPath });
35459
+ const dirty = (await runGit(["diff", "--name-only"])).trim().length > 0;
35460
+ commit = await attempt(
35461
+ async () => (await runGit(["rev-parse", "HEAD"])).trim()
35462
+ );
33508
35463
  commit_message = await attempt(
33509
- async () => (await git.raw(["log", "-1", "--pretty=%B"])).trim()
35464
+ async () => (await runGit(["log", "-1", "--pretty=%B"])).trim()
33510
35465
  );
33511
35466
  commit_time = await attempt(
33512
- async () => (await git.raw(["log", "-1", "--pretty=%cI"])).trim()
35467
+ async () => (await runGit(["log", "-1", "--pretty=%cI"])).trim()
33513
35468
  );
33514
35469
  author_name = await attempt(
33515
- async () => (await git.raw(["log", "-1", "--pretty=%aN"])).trim()
35470
+ async () => (await runGit(["log", "-1", "--pretty=%aN"])).trim()
33516
35471
  );
33517
35472
  author_email = await attempt(
33518
- async () => (await git.raw(["log", "-1", "--pretty=%aE"])).trim()
35473
+ async () => (await runGit(["log", "-1", "--pretty=%aE"])).trim()
33519
35474
  );
33520
35475
  tag = await attempt(
33521
- async () => (await git.raw(["describe", "--tags", "--exact-match", "--always"])).trim()
35476
+ async () => (await runGit(["describe", "--tags", "--exact-match", "--always"])).trim()
33522
35477
  );
33523
35478
  branch = await attempt(
33524
- async () => (await git.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim()
35479
+ async () => (await runGit(["rev-parse", "--abbrev-ref", "HEAD"])).trim()
33525
35480
  );
33526
35481
  if (dirty) {
33527
35482
  git_diff = await attempt(
33528
- async () => truncateToByteLimit(await git.raw(["--no-ext-diff", "diff", "HEAD"]))
35483
+ async () => truncateToByteLimit(await runGit(["diff", "--no-ext-diff", "HEAD"]))
33529
35484
  );
33530
35485
  }
33531
35486
  return {
@@ -33606,9 +35561,9 @@ function configureNode() {
33606
35561
  return value;
33607
35562
  }
33608
35563
  const envPaths = [];
33609
- for (let dir = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir = path.dirname(dir), depth++) {
33610
- envPaths.push(path.join(dir, ".env.braintrust"));
33611
- if (path.dirname(dir) === dir) {
35564
+ for (let dir = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir = path2.dirname(dir), depth++) {
35565
+ envPaths.push(path2.join(dir, ".env.braintrust"));
35566
+ if (path2.dirname(dir) === dir) {
33612
35567
  break;
33613
35568
  }
33614
35569
  }
@@ -33650,10 +35605,10 @@ function configureNode() {
33650
35605
  isomorph_default.processOn = (event, handler) => {
33651
35606
  process.on(event, handler);
33652
35607
  };
33653
- isomorph_default.basename = path.basename;
35608
+ isomorph_default.basename = path2.basename;
33654
35609
  isomorph_default.writeln = (text) => process.stdout.write(text + "\n");
33655
- isomorph_default.pathJoin = path.join;
33656
- isomorph_default.pathDirname = path.dirname;
35610
+ isomorph_default.pathJoin = path2.join;
35611
+ isomorph_default.pathDirname = path2.dirname;
33657
35612
  isomorph_default.mkdir = fs.mkdir;
33658
35613
  isomorph_default.writeFile = fs.writeFile;
33659
35614
  isomorph_default.readFile = fs.readFile;
@@ -33688,8 +35643,8 @@ function configureNode() {
33688
35643
  registry.enable();
33689
35644
  }
33690
35645
  function getNearestBraintrustEnvValue(name) {
33691
- for (let dir = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir = path.dirname(dir), depth++) {
33692
- const envPath = path.join(dir, ".env.braintrust");
35646
+ for (let dir = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir = path2.dirname(dir), depth++) {
35647
+ const envPath = path2.join(dir, ".env.braintrust");
33693
35648
  try {
33694
35649
  const parsed = dotenv.parse(fsSync.readFileSync(envPath, "utf8"));
33695
35650
  const value = parsed[name];
@@ -33699,7 +35654,7 @@ function getNearestBraintrustEnvValue(name) {
33699
35654
  return void 0;
33700
35655
  }
33701
35656
  }
33702
- if (path.dirname(dir) === dir) {
35657
+ if (path2.dirname(dir) === dir) {
33703
35658
  break;
33704
35659
  }
33705
35660
  }
@@ -33757,9 +35712,10 @@ export {
33757
35712
  TRACESTATE_HEADER,
33758
35713
  BAGGAGE_HEADER,
33759
35714
  BRAINTRUST_PARENT_KEY,
35715
+ uint8ArrayToBase64,
35716
+ base64ToUint8Array,
33760
35717
  spanObjectTypeV3ToTypedString,
33761
35718
  isObject,
33762
- mergeDicts,
33763
35719
  slugify,
33764
35720
  SpanComponentsV4,
33765
35721
  makeScorerPropagatedEvent,
@@ -33810,6 +35766,7 @@ export {
33810
35766
  ReadonlyAttachment,
33811
35767
  JSONAttachment,
33812
35768
  updateSpan,
35769
+ _internalResumeSpan,
33813
35770
  spanComponentsToObjectId,
33814
35771
  ERR_PERMALINK,
33815
35772
  permalink,
@@ -33871,7 +35828,9 @@ export {
33871
35828
  X_CACHED_HEADER,
33872
35829
  parseCachedHeader,
33873
35830
  finalizeAnthropicTokens,
35831
+ toNumericMetrics,
33874
35832
  extractAnthropicCacheTokens,
35833
+ collectAnthropicSession,
33875
35834
  zodToJsonSchema,
33876
35835
  currentWorkflowAgentWrapperSpan,
33877
35836
  braintrustAISDKTelemetry,