braintrust 3.9.0 → 3.10.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 (42) hide show
  1. package/dev/dist/index.d.mts +107 -1
  2. package/dev/dist/index.d.ts +107 -1
  3. package/dev/dist/index.js +2126 -443
  4. package/dev/dist/index.mjs +1814 -131
  5. package/dist/auto-instrumentations/bundler/esbuild.cjs +166 -0
  6. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  7. package/dist/auto-instrumentations/bundler/rollup.cjs +166 -0
  8. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/vite.cjs +166 -0
  10. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  11. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +163 -0
  12. package/dist/auto-instrumentations/bundler/webpack.cjs +166 -0
  13. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  14. package/dist/auto-instrumentations/{chunk-KIMMUFAK.mjs → chunk-GZNXBBPU.mjs} +164 -1
  15. package/dist/auto-instrumentations/{chunk-G7F6HZGE.mjs → chunk-XWEQQOQH.mjs} +8 -1
  16. package/dist/auto-instrumentations/hook.mjs +255 -8
  17. package/dist/auto-instrumentations/index.cjs +256 -7
  18. package/dist/auto-instrumentations/index.d.mts +5 -1
  19. package/dist/auto-instrumentations/index.d.ts +5 -1
  20. package/dist/auto-instrumentations/index.mjs +96 -8
  21. package/dist/browser.d.mts +141 -7
  22. package/dist/browser.d.ts +141 -7
  23. package/dist/browser.js +2035 -140
  24. package/dist/browser.mjs +2035 -140
  25. package/dist/cli.js +1822 -139
  26. package/dist/edge-light.d.mts +1 -1
  27. package/dist/edge-light.d.ts +1 -1
  28. package/dist/edge-light.js +2035 -140
  29. package/dist/edge-light.mjs +2035 -140
  30. package/dist/index.d.mts +141 -7
  31. package/dist/index.d.ts +141 -7
  32. package/dist/index.js +2397 -502
  33. package/dist/index.mjs +2035 -140
  34. package/dist/instrumentation/index.d.mts +7 -0
  35. package/dist/instrumentation/index.d.ts +7 -0
  36. package/dist/instrumentation/index.js +1662 -167
  37. package/dist/instrumentation/index.mjs +1662 -167
  38. package/dist/workerd.d.mts +1 -1
  39. package/dist/workerd.d.ts +1 -1
  40. package/dist/workerd.js +2035 -140
  41. package/dist/workerd.mjs +2035 -140
  42. package/package.json +6 -6
@@ -1922,6 +1922,7 @@ var TopicMapData = import_v36.z.object({
1922
1922
  report_key: import_v36.z.string().optional(),
1923
1923
  topic_names: import_v36.z.record(import_v36.z.string()).optional(),
1924
1924
  generation_settings: TopicMapGenerationSettings.optional(),
1925
+ disable_reconciliation: import_v36.z.boolean().optional(),
1925
1926
  distance_threshold: import_v36.z.number().optional()
1926
1927
  });
1927
1928
  var BatchedFacetData = import_v36.z.object({
@@ -2252,28 +2253,6 @@ var EnvVar = import_v36.z.object({
2252
2253
  secret_type: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2253
2254
  secret_category: import_v36.z.enum(["env_var", "ai_provider", "sandbox_provider"]).optional().default("env_var")
2254
2255
  });
2255
- var EvalStatusPageTheme = import_v36.z.enum(["light", "dark"]);
2256
- var EvalStatusPageConfig = import_v36.z.object({
2257
- score_columns: import_v36.z.union([import_v36.z.array(import_v36.z.string()), import_v36.z.null()]),
2258
- metric_columns: import_v36.z.union([import_v36.z.array(import_v36.z.string()), import_v36.z.null()]),
2259
- grouping_field: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]),
2260
- filter: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]),
2261
- sort_by: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]),
2262
- sort_order: import_v36.z.union([import_v36.z.enum(["asc", "desc"]), import_v36.z.null()]),
2263
- api_key: import_v36.z.union([import_v36.z.string(), import_v36.z.null()])
2264
- }).partial();
2265
- var EvalStatusPage = import_v36.z.object({
2266
- id: import_v36.z.string().uuid(),
2267
- project_id: import_v36.z.string().uuid(),
2268
- user_id: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2269
- created: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2270
- deleted_at: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2271
- name: import_v36.z.string(),
2272
- description: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2273
- logo_url: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2274
- theme: EvalStatusPageTheme,
2275
- config: EvalStatusPageConfig
2276
- });
2277
2256
  var RepoInfo = import_v36.z.union([
2278
2257
  import_v36.z.object({
2279
2258
  commit: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]),
@@ -2300,6 +2279,15 @@ var Experiment = import_v36.z.object({
2300
2279
  deleted_at: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2301
2280
  dataset_id: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2302
2281
  dataset_version: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2282
+ internal_metadata: import_v36.z.union([
2283
+ import_v36.z.object({
2284
+ dataset_filter: import_v36.z.union([
2285
+ import_v36.z.object({}).partial().passthrough(),
2286
+ import_v36.z.null()
2287
+ ])
2288
+ }).partial().passthrough(),
2289
+ import_v36.z.null()
2290
+ ]).optional(),
2303
2291
  parameters_id: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2304
2292
  parameters_version: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2305
2293
  public: import_v36.z.boolean(),
@@ -3036,14 +3024,21 @@ var ProjectAutomation = import_v36.z.object({
3036
3024
  import_v36.z.object({ type: import_v36.z.literal("log_spans") }),
3037
3025
  import_v36.z.object({ type: import_v36.z.literal("btql_query"), btql_query: import_v36.z.string() })
3038
3026
  ]),
3027
+ scope: import_v36.z.union([SpanScope, TraceScope, GroupScope, import_v36.z.null()]).optional(),
3039
3028
  export_path: import_v36.z.string(),
3040
3029
  format: import_v36.z.enum(["jsonl", "parquet"]),
3041
3030
  interval_seconds: import_v36.z.number().gte(1).lte(2592e3),
3042
- credentials: import_v36.z.object({
3043
- type: import_v36.z.literal("aws_iam"),
3044
- role_arn: import_v36.z.string(),
3045
- external_id: import_v36.z.string()
3046
- }),
3031
+ credentials: import_v36.z.union([
3032
+ import_v36.z.object({
3033
+ type: import_v36.z.literal("aws_iam"),
3034
+ role_arn: import_v36.z.string(),
3035
+ external_id: import_v36.z.string()
3036
+ }),
3037
+ import_v36.z.object({
3038
+ type: import_v36.z.literal("gcp_service_account"),
3039
+ service_account_email: import_v36.z.string()
3040
+ })
3041
+ ]),
3047
3042
  batch_size: import_v36.z.union([import_v36.z.number(), import_v36.z.null()]).optional()
3048
3043
  }),
3049
3044
  import_v36.z.object({
@@ -3423,7 +3418,7 @@ var ViewOptions = import_v36.z.union([
3423
3418
  import_v36.z.object({ from: import_v36.z.string(), to: import_v36.z.string() }),
3424
3419
  import_v36.z.null()
3425
3420
  ]),
3426
- queryShape: import_v36.z.union([import_v36.z.enum(["traces", "spans"]), import_v36.z.null()]),
3421
+ queryShape: import_v36.z.union([import_v36.z.enum(["traces", "spans", "topics"]), import_v36.z.null()]),
3427
3422
  cluster: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]),
3428
3423
  freezeColumns: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()])
3429
3424
  }).partial(),
@@ -4409,6 +4404,19 @@ var RESET_CONTEXT_MANAGER_STATE = Symbol.for(
4409
4404
  "braintrust.resetContextManagerState"
4410
4405
  );
4411
4406
  var DEFAULT_MAX_REQUEST_SIZE = 6 * 1024 * 1024;
4407
+ var datasetSnapshotRegisterResponseSchema = import_v38.z.object({
4408
+ dataset_snapshot: DatasetSnapshot,
4409
+ found_existing: import_v38.z.boolean().optional()
4410
+ });
4411
+ var datasetRestorePreviewResultSchema = import_v38.z.object({
4412
+ rows_to_restore: import_v38.z.number(),
4413
+ rows_to_delete: import_v38.z.number()
4414
+ });
4415
+ var datasetRestoreResultSchema = import_v38.z.object({
4416
+ xact_id: import_v38.z.string().nullable(),
4417
+ rows_restored: import_v38.z.number(),
4418
+ rows_deleted: import_v38.z.number()
4419
+ });
4412
4420
  var parametersRowSchema = import_v38.z.object({
4413
4421
  id: import_v38.z.string().uuid(),
4414
4422
  _xact_id: import_v38.z.string(),
@@ -6405,6 +6413,40 @@ Error: ${errorText}`;
6405
6413
  this.queue.enforceQueueSizeLimit(enforce);
6406
6414
  }
6407
6415
  };
6416
+ function isDatasetSnapshotNameLookup(lookup) {
6417
+ return "snapshotName" in lookup;
6418
+ }
6419
+ function assertDatasetSnapshotLookup(lookup) {
6420
+ const hasSnapshotName = lookup.snapshotName !== void 0;
6421
+ const hasXactId = lookup.xactId !== void 0;
6422
+ if (hasSnapshotName === hasXactId) {
6423
+ throw new Error("Exactly one of snapshotName or xactId must be provided");
6424
+ }
6425
+ }
6426
+ function getInternalBtqlLimit(internalBtql) {
6427
+ const limit = internalBtql?.["limit"];
6428
+ return typeof limit === "number" ? limit : void 0;
6429
+ }
6430
+ async function getDatasetSnapshots(params) {
6431
+ const { state, datasetId } = params;
6432
+ return DatasetSnapshot.array().parse(
6433
+ await state.appConn().post_json("api/dataset_snapshot/get", {
6434
+ dataset_id: datasetId,
6435
+ ..."snapshotName" in params ? { name: params.snapshotName } : {},
6436
+ ..."xactId" in params ? { xact_id: params.xactId } : {}
6437
+ })
6438
+ );
6439
+ }
6440
+ async function getDatasetSnapshot(params) {
6441
+ assertDatasetSnapshotLookup(params);
6442
+ const snapshots = await getDatasetSnapshots(params);
6443
+ if (snapshots.length > 1) {
6444
+ throw new Error(
6445
+ isDatasetSnapshotNameLookup(params) ? `Expected a unique dataset snapshot named "${params.snapshotName}" for ${params.datasetId}` : `Expected a unique dataset snapshot for xact_id "${params.xactId}" in ${params.datasetId}`
6446
+ );
6447
+ }
6448
+ return snapshots[0];
6449
+ }
6408
6450
  async function computeLoggerMetadata(state, {
6409
6451
  project_name,
6410
6452
  project_id
@@ -6819,11 +6861,20 @@ var ObjectFetcher = class {
6819
6861
  async getState() {
6820
6862
  throw new Error("ObjectFetcher subclasses must have a 'getState' method");
6821
6863
  }
6864
+ getPinnedVersion() {
6865
+ return this.pinnedVersion;
6866
+ }
6867
+ setPinnedVersion(pinnedVersion) {
6868
+ this.pinnedVersion = pinnedVersion;
6869
+ }
6870
+ getInternalBtql() {
6871
+ return this._internal_btql;
6872
+ }
6822
6873
  async *fetchRecordsFromApi(batchSize) {
6823
6874
  const state = await this.getState();
6824
6875
  const objectId = await this.id;
6825
6876
  const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
6826
- const internalLimit = this._internal_btql?.limit;
6877
+ const internalLimit = getInternalBtqlLimit(this._internal_btql);
6827
6878
  const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
6828
6879
  const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
6829
6880
  Object.entries(this._internal_btql ?? {}).filter(
@@ -7597,7 +7648,7 @@ function splitLoggingData({
7597
7648
  return [serializableInternalData, lazyInternalData];
7598
7649
  }
7599
7650
  var Dataset2 = class extends ObjectFetcher {
7600
- constructor(state, lazyMetadata, pinnedVersion, legacy, _internal_btql) {
7651
+ constructor(state, lazyMetadata, pinnedVersion, legacy, _internal_btql, pinState) {
7601
7652
  const isLegacyDataset = legacy ?? DEFAULT_IS_LEGACY_DATASET;
7602
7653
  if (isLegacyDataset) {
7603
7654
  debugLogger.forState(state).warn(
@@ -7618,10 +7669,16 @@ var Dataset2 = class extends ObjectFetcher {
7618
7669
  );
7619
7670
  this.state = state;
7620
7671
  this.lazyMetadata = lazyMetadata;
7672
+ this.lazyPinnedVersion = pinState?.lazyPinnedVersion;
7673
+ this.pinnedEnvironment = pinState?.pinnedEnvironment;
7674
+ this.pinnedSnapshotName = pinState?.pinnedSnapshotName;
7621
7675
  }
7622
7676
  lazyMetadata;
7623
7677
  __braintrust_dataset_marker = true;
7624
7678
  newRecords = 0;
7679
+ lazyPinnedVersion;
7680
+ pinnedEnvironment;
7681
+ pinnedSnapshotName;
7625
7682
  get id() {
7626
7683
  return (async () => {
7627
7684
  return (await this.lazyMetadata.get()).dataset.id;
@@ -7640,10 +7697,40 @@ var Dataset2 = class extends ObjectFetcher {
7640
7697
  get loggingState() {
7641
7698
  return this.state;
7642
7699
  }
7700
+ async toEvalData() {
7701
+ await this.getState();
7702
+ const metadata = await this.lazyMetadata.get();
7703
+ const pinnedVersion = this.getPinnedVersion();
7704
+ const internalBtql = this.getInternalBtql();
7705
+ return {
7706
+ dataset_id: metadata.dataset.id,
7707
+ ...this.pinnedEnvironment !== void 0 ? {
7708
+ dataset_environment: this.pinnedEnvironment
7709
+ } : {},
7710
+ ...this.pinnedEnvironment === void 0 && this.pinnedSnapshotName !== void 0 ? {
7711
+ dataset_snapshot_name: this.pinnedSnapshotName
7712
+ } : {},
7713
+ ...this.pinnedEnvironment === void 0 && this.pinnedSnapshotName === void 0 && pinnedVersion !== void 0 ? {
7714
+ dataset_version: pinnedVersion
7715
+ } : {},
7716
+ ...internalBtql !== void 0 ? { _internal_btql: internalBtql } : {}
7717
+ };
7718
+ }
7643
7719
  async getState() {
7644
7720
  await this.lazyMetadata.get();
7721
+ if (this.lazyPinnedVersion !== void 0 && this.getPinnedVersion() === void 0) {
7722
+ this.setPinnedVersion(await this.lazyPinnedVersion.get());
7723
+ }
7645
7724
  return this.state;
7646
7725
  }
7726
+ async version(options) {
7727
+ const pinnedVersion = this.getPinnedVersion();
7728
+ if (pinnedVersion !== void 0) {
7729
+ return pinnedVersion;
7730
+ }
7731
+ await this.getState();
7732
+ return await super.version(options);
7733
+ }
7647
7734
  validateEvent({
7648
7735
  metadata,
7649
7736
  expected,
@@ -7779,6 +7866,88 @@ var Dataset2 = class extends ObjectFetcher {
7779
7866
  this.state.bgLogger().log([args]);
7780
7867
  return id;
7781
7868
  }
7869
+ async createSnapshot({
7870
+ name,
7871
+ description,
7872
+ update
7873
+ }) {
7874
+ await this.flush();
7875
+ const state = await this.getState();
7876
+ const datasetId = await this.id;
7877
+ const currentVersion = await this.version();
7878
+ if (currentVersion === void 0) {
7879
+ throw new Error("Cannot create snapshot: dataset has no version");
7880
+ }
7881
+ const response = await state.appConn().post_json("api/dataset_snapshot/register", {
7882
+ dataset_id: datasetId,
7883
+ dataset_snapshot_name: name,
7884
+ description,
7885
+ xact_id: currentVersion,
7886
+ update
7887
+ });
7888
+ return datasetSnapshotRegisterResponseSchema.parse(response).dataset_snapshot;
7889
+ }
7890
+ async listSnapshots() {
7891
+ const state = await this.getState();
7892
+ return await getDatasetSnapshots({
7893
+ state,
7894
+ datasetId: await this.id
7895
+ });
7896
+ }
7897
+ async getSnapshot(lookup) {
7898
+ const state = await this.getState();
7899
+ const datasetId = await this.id;
7900
+ return await getDatasetSnapshot({
7901
+ state,
7902
+ datasetId,
7903
+ ...lookup
7904
+ });
7905
+ }
7906
+ async updateSnapshot(snapshotId, {
7907
+ name,
7908
+ description
7909
+ }) {
7910
+ const state = await this.getState();
7911
+ return DatasetSnapshot.parse(
7912
+ await state.appConn().post_json("api/dataset_snapshot/patch_id", {
7913
+ id: snapshotId,
7914
+ name,
7915
+ description
7916
+ })
7917
+ );
7918
+ }
7919
+ async deleteSnapshot(snapshotId) {
7920
+ const state = await this.getState();
7921
+ return DatasetSnapshot.parse(
7922
+ await state.appConn().post_json("api/dataset_snapshot/delete_id", {
7923
+ id: snapshotId
7924
+ })
7925
+ );
7926
+ }
7927
+ async restorePreview({
7928
+ version
7929
+ }) {
7930
+ await this.flush();
7931
+ const state = await this.getState();
7932
+ const datasetId = await this.id;
7933
+ return datasetRestorePreviewResultSchema.parse(
7934
+ await state.apiConn().post_json(`v1/dataset/${datasetId}/restore/preview`, {
7935
+ version
7936
+ })
7937
+ );
7938
+ }
7939
+ async restore({
7940
+ version
7941
+ }) {
7942
+ await this.flush();
7943
+ const state = await this.getState();
7944
+ const datasetId = await this.id;
7945
+ return datasetRestoreResultSchema.parse(
7946
+ await state.apiConn().post_json(`v1/dataset/${datasetId}/restore`, {
7947
+ version
7948
+ })
7949
+ );
7950
+ }
7782
7951
  /**
7783
7952
  * Summarize the dataset, including high level metrics about its size and other metadata.
7784
7953
  * @param summarizeData Whether to summarize the data. If false, only the metadata will be returned.
@@ -12294,6 +12463,9 @@ function llmParentKey(parentToolUseId) {
12294
12463
  function isSubAgentDelegationToolName(toolName) {
12295
12464
  return toolName === "Agent" || toolName === "Task";
12296
12465
  }
12466
+ function shouldParentToolAsTaskSibling(toolName) {
12467
+ return toolName === "Agent" || toolName === "Task" || toolName === "Bash";
12468
+ }
12297
12469
  function filterSerializableOptions(options) {
12298
12470
  const allowedKeys = [
12299
12471
  "model",
@@ -12393,6 +12565,11 @@ function resolveTaskToolUseId(taskIdToToolUseId, message) {
12393
12565
  }
12394
12566
  return void 0;
12395
12567
  }
12568
+ function seedTaskToolUseIdMapping(taskIdToToolUseId, message) {
12569
+ if (typeof message.task_id === "string" && typeof message.tool_use_id === "string") {
12570
+ taskIdToToolUseId.set(message.task_id, message.tool_use_id);
12571
+ }
12572
+ }
12396
12573
  function extractUsageFromMessage(message) {
12397
12574
  const metrics = {};
12398
12575
  let usage;
@@ -12588,7 +12765,10 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
12588
12765
  }
12589
12766
  },
12590
12767
  name: parsed.displayName,
12591
- parent: await resolveParentSpan(toolUseID),
12768
+ parent: await resolveParentSpan(toolUseID, {
12769
+ agentId: input.agent_id,
12770
+ preferTaskSiblingParent: shouldParentToolAsTaskSibling(parsed.toolName)
12771
+ }),
12592
12772
  spanAttributes: { type: "tool" /* TOOL */ }
12593
12773
  });
12594
12774
  activeToolSpans.set(toolUseID, toolSpan);
@@ -12878,6 +13058,7 @@ async function finalizeCurrentMessageGroup(state) {
12878
13058
  state.currentMessages.length = 0;
12879
13059
  }
12880
13060
  function maybeTrackToolUseContext(state, message) {
13061
+ seedTaskToolUseIdMapping(state.taskIdToToolUseId, message);
12881
13062
  if (message.type !== "assistant" || !Array.isArray(message.message?.content)) {
12882
13063
  return;
12883
13064
  }
@@ -12932,6 +13113,34 @@ async function ensureSubAgentSpan(subAgentDetailsByToolUseId, rootSpan, activeTo
12932
13113
  subAgentSpans.set(parentToolUseId, subAgentSpan);
12933
13114
  return subAgentSpan;
12934
13115
  }
13116
+ async function ensureActiveLlmSpanForParentToolUse(rootSpan, activeLlmSpansByParentToolUse, subAgentDetailsByToolUseId, activeToolSpans, subAgentSpans, parentToolUseId, startTime) {
13117
+ const parentKey = llmParentKey(parentToolUseId);
13118
+ const existingLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
13119
+ if (existingLlmSpan) {
13120
+ return existingLlmSpan;
13121
+ }
13122
+ let llmParentSpan = await rootSpan.export();
13123
+ if (parentToolUseId) {
13124
+ const subAgentSpan = await ensureSubAgentSpan(
13125
+ subAgentDetailsByToolUseId,
13126
+ rootSpan,
13127
+ activeToolSpans,
13128
+ subAgentSpans,
13129
+ parentToolUseId
13130
+ );
13131
+ llmParentSpan = await subAgentSpan.export();
13132
+ }
13133
+ const llmSpan = startSpan({
13134
+ name: "anthropic.messages.create",
13135
+ parent: llmParentSpan,
13136
+ spanAttributes: {
13137
+ type: "llm" /* LLM */
13138
+ },
13139
+ startTime
13140
+ });
13141
+ activeLlmSpansByParentToolUse.set(parentKey, llmSpan);
13142
+ return llmSpan;
13143
+ }
12935
13144
  async function maybeHandleTaskLifecycleMessage(state, message) {
12936
13145
  if (message.type !== "system") {
12937
13146
  return false;
@@ -13041,29 +13250,15 @@ async function handleStreamMessage(state, message) {
13041
13250
  }
13042
13251
  if (message.type === "assistant" && message.message?.usage) {
13043
13252
  const parentToolUseId = message.parent_tool_use_id ?? null;
13044
- const parentKey = llmParentKey(parentToolUseId);
13045
- if (!state.activeLlmSpansByParentToolUse.has(parentKey)) {
13046
- let llmParentSpan = await state.span.export();
13047
- if (parentToolUseId) {
13048
- const subAgentSpan = await ensureSubAgentSpan(
13049
- state.subAgentDetailsByToolUseId,
13050
- state.span,
13051
- state.activeToolSpans,
13052
- state.subAgentSpans,
13053
- parentToolUseId
13054
- );
13055
- llmParentSpan = await subAgentSpan.export();
13056
- }
13057
- const llmSpan = startSpan({
13058
- name: "anthropic.messages.create",
13059
- parent: llmParentSpan,
13060
- spanAttributes: {
13061
- type: "llm" /* LLM */
13062
- },
13063
- startTime: state.currentMessageStartTime
13064
- });
13065
- state.activeLlmSpansByParentToolUse.set(parentKey, llmSpan);
13066
- }
13253
+ await ensureActiveLlmSpanForParentToolUse(
13254
+ state.span,
13255
+ state.activeLlmSpansByParentToolUse,
13256
+ state.subAgentDetailsByToolUseId,
13257
+ state.activeToolSpans,
13258
+ state.subAgentSpans,
13259
+ parentToolUseId,
13260
+ state.currentMessageStartTime
13261
+ );
13067
13262
  state.currentMessages.push(message);
13068
13263
  }
13069
13264
  if (message.type !== "result" || !message.usage) {
@@ -13210,10 +13405,35 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
13210
13405
  const localToolContext = createClaudeLocalToolContext();
13211
13406
  const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
13212
13407
  const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
13213
- const resolveToolUseParentSpan = async (toolUseID) => {
13214
- const parentToolUseId = toolUseToParent.get(toolUseID) ?? null;
13408
+ const resolveToolUseParentSpan = async (toolUseID, context) => {
13409
+ const trackedParentToolUseId = toolUseToParent.get(toolUseID);
13410
+ const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
13215
13411
  const parentKey = llmParentKey(parentToolUseId);
13216
13412
  const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
13413
+ if (context?.preferTaskSiblingParent) {
13414
+ if (!activeLlmSpan) {
13415
+ await ensureActiveLlmSpanForParentToolUse(
13416
+ span,
13417
+ activeLlmSpansByParentToolUse,
13418
+ subAgentDetailsByToolUseId,
13419
+ activeToolSpans,
13420
+ subAgentSpans,
13421
+ parentToolUseId,
13422
+ getCurrentUnixTimestamp()
13423
+ );
13424
+ }
13425
+ if (parentToolUseId) {
13426
+ const subAgentSpan = await ensureSubAgentSpan(
13427
+ subAgentDetailsByToolUseId,
13428
+ span,
13429
+ activeToolSpans,
13430
+ subAgentSpans,
13431
+ parentToolUseId
13432
+ );
13433
+ return subAgentSpan.export();
13434
+ }
13435
+ return span.export();
13436
+ }
13217
13437
  if (activeLlmSpan) {
13218
13438
  return activeLlmSpan.export();
13219
13439
  }
@@ -13341,135 +13561,1013 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
13341
13561
  }
13342
13562
  };
13343
13563
 
13344
- // src/instrumentation/plugins/google-genai-channels.ts
13345
- var googleGenAIChannels = defineChannels("@google/genai", {
13346
- generateContent: channel({
13347
- channelName: "models.generateContent",
13564
+ // src/instrumentation/plugins/cursor-sdk-channels.ts
13565
+ var cursorSDKChannels = defineChannels("@cursor/sdk", {
13566
+ create: channel({
13567
+ channelName: "Agent.create",
13348
13568
  kind: "async"
13349
13569
  }),
13350
- generateContentStream: channel({
13351
- channelName: "models.generateContentStream",
13570
+ resume: channel({
13571
+ channelName: "Agent.resume",
13352
13572
  kind: "async"
13353
13573
  }),
13354
- embedContent: channel({
13355
- channelName: "models.embedContent",
13574
+ prompt: channel({
13575
+ channelName: "Agent.prompt",
13576
+ kind: "async"
13577
+ }),
13578
+ send: channel({
13579
+ channelName: "agent.send",
13356
13580
  kind: "async"
13357
13581
  })
13358
13582
  });
13359
13583
 
13360
- // src/instrumentation/plugins/google-genai-plugin.ts
13361
- var GOOGLE_GENAI_INTERNAL_CONTEXT = {
13362
- caller_filename: "<node-internal>",
13363
- caller_functionname: "<node-internal>",
13364
- caller_lineno: 0
13365
- };
13366
- function createWrapperParityEvent(args) {
13367
- return {
13368
- context: GOOGLE_GENAI_INTERNAL_CONTEXT,
13369
- input: args.input,
13370
- metadata: args.metadata
13371
- };
13372
- }
13373
- var GoogleGenAIPlugin = class extends BasePlugin {
13584
+ // src/instrumentation/plugins/cursor-sdk-plugin.ts
13585
+ var PATCHED_AGENT = Symbol.for("braintrust.cursor-sdk.auto-patched-agent");
13586
+ var PATCHED_RUN = Symbol.for("braintrust.cursor-sdk.patched-run");
13587
+ var WRAPPED_AGENT = Symbol.for("braintrust.cursor-sdk.wrapped-agent");
13588
+ var CursorSDKPlugin = class extends BasePlugin {
13589
+ promptDepth = 0;
13374
13590
  onEnable() {
13375
- this.subscribeToGoogleGenAIChannels();
13591
+ this.subscribeToAgentFactories();
13592
+ this.subscribeToPrompt();
13593
+ this.subscribeToSend();
13376
13594
  }
13377
13595
  onDisable() {
13378
- this.unsubscribers = unsubscribeAll(this.unsubscribers);
13596
+ for (const unsubscribe of this.unsubscribers) {
13597
+ unsubscribe();
13598
+ }
13599
+ this.unsubscribers = [];
13600
+ this.promptDepth = 0;
13379
13601
  }
13380
- subscribeToGoogleGenAIChannels() {
13381
- this.subscribeToGenerateContentChannel();
13382
- this.subscribeToGenerateContentStreamChannel();
13383
- this.subscribeToEmbedContentChannel();
13602
+ subscribeToAgentFactories() {
13603
+ this.subscribeToAgentFactory(cursorSDKChannels.create);
13604
+ this.subscribeToAgentFactory(cursorSDKChannels.resume);
13384
13605
  }
13385
- subscribeToGenerateContentChannel() {
13386
- const tracingChannel = googleGenAIChannels.generateContent.tracingChannel();
13387
- const states = /* @__PURE__ */ new WeakMap();
13388
- const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
13389
- tracingChannel,
13390
- states,
13391
- (event) => {
13392
- const params = event.arguments[0];
13393
- const input = serializeGenerateContentInput(params);
13394
- const metadata = extractGenerateContentMetadata(params);
13395
- const span = startSpan({
13396
- name: "generate_content",
13397
- spanAttributes: {
13398
- type: "llm" /* LLM */
13399
- },
13400
- event: createWrapperParityEvent({ input, metadata })
13401
- });
13402
- return {
13403
- span,
13404
- startTime: getCurrentUnixTimestamp()
13405
- };
13606
+ subscribeToAgentFactory(channel2) {
13607
+ const tracingChannel = channel2.tracingChannel();
13608
+ const handlers = {
13609
+ asyncEnd: (event) => {
13610
+ patchCursorAgentInPlace(event.result);
13611
+ },
13612
+ error: () => {
13406
13613
  }
13407
- );
13614
+ };
13615
+ tracingChannel.subscribe(handlers);
13616
+ this.unsubscribers.push(() => {
13617
+ tracingChannel.unsubscribe(handlers);
13618
+ });
13619
+ }
13620
+ subscribeToPrompt() {
13621
+ const channel2 = cursorSDKChannels.prompt.tracingChannel();
13622
+ const states = /* @__PURE__ */ new WeakMap();
13408
13623
  const handlers = {
13409
13624
  start: (event) => {
13410
- ensureSpanState(states, event, () => {
13411
- const params = event.arguments[0];
13412
- const input = serializeGenerateContentInput(params);
13413
- const metadata = extractGenerateContentMetadata(params);
13414
- const span = startSpan({
13415
- name: "generate_content",
13416
- spanAttributes: {
13417
- type: "llm" /* LLM */
13418
- },
13419
- event: createWrapperParityEvent({ input, metadata })
13420
- });
13421
- return {
13422
- span,
13423
- startTime: getCurrentUnixTimestamp()
13424
- };
13625
+ this.promptDepth += 1;
13626
+ const message = event.arguments[0];
13627
+ const options = event.arguments[1];
13628
+ const metadata = {
13629
+ ...extractAgentOptionsMetadata(options),
13630
+ "cursor_sdk.operation": "Agent.prompt",
13631
+ provider: "cursor",
13632
+ ...event.moduleVersion ? { "cursor_sdk.version": event.moduleVersion } : {}
13633
+ };
13634
+ const span = startSpan({
13635
+ name: "Cursor Agent",
13636
+ spanAttributes: { type: "task" /* TASK */ }
13425
13637
  });
13638
+ const startTime = getCurrentUnixTimestamp();
13639
+ safeLog(span, {
13640
+ input: sanitizeUserMessage(message),
13641
+ metadata
13642
+ });
13643
+ states.set(event, { metadata, span, startTime });
13426
13644
  },
13427
13645
  asyncEnd: (event) => {
13428
- const spanState = states.get(event);
13429
- if (!spanState) {
13646
+ this.promptDepth = Math.max(0, this.promptDepth - 1);
13647
+ const state = states.get(event);
13648
+ if (!state) {
13430
13649
  return;
13431
13650
  }
13432
13651
  try {
13433
- const responseMetadata = extractResponseMetadata(event.result);
13434
- spanState.span.log({
13435
- ...responseMetadata ? { metadata: responseMetadata } : {},
13436
- metrics: cleanMetrics(
13437
- extractGenerateContentMetrics(
13438
- event.result,
13439
- spanState.startTime
13440
- )
13441
- ),
13442
- output: event.result
13652
+ safeLog(state.span, {
13653
+ metadata: {
13654
+ ...state.metadata,
13655
+ ...extractRunResultMetadata(event.result)
13656
+ },
13657
+ metrics: buildDurationMetrics(state.startTime),
13658
+ output: event.result?.result ?? event.result
13443
13659
  });
13444
13660
  } finally {
13445
- spanState.span.end();
13661
+ state.span.end();
13446
13662
  states.delete(event);
13447
13663
  }
13448
13664
  },
13449
13665
  error: (event) => {
13450
- logErrorAndEndSpan(states, event);
13666
+ this.promptDepth = Math.max(0, this.promptDepth - 1);
13667
+ const state = states.get(event);
13668
+ if (!state || !event.error) {
13669
+ return;
13670
+ }
13671
+ safeLog(state.span, { error: event.error.message });
13672
+ state.span.end();
13673
+ states.delete(event);
13451
13674
  }
13452
13675
  };
13453
- tracingChannel.subscribe(handlers);
13676
+ channel2.subscribe(handlers);
13454
13677
  this.unsubscribers.push(() => {
13455
- unbindCurrentSpanStore?.();
13456
- tracingChannel.unsubscribe(handlers);
13678
+ channel2.unsubscribe(handlers);
13457
13679
  });
13458
13680
  }
13459
- subscribeToGenerateContentStreamChannel() {
13460
- const tracingChannel = googleGenAIChannels.generateContentStream.tracingChannel();
13681
+ subscribeToSend() {
13682
+ const channel2 = cursorSDKChannels.send.tracingChannel();
13683
+ const states = /* @__PURE__ */ new WeakMap();
13461
13684
  const handlers = {
13462
13685
  start: (event) => {
13463
- const streamEvent = event;
13464
- const params = event.arguments[0];
13465
- streamEvent.googleGenAIInput = serializeGenerateContentInput(params);
13466
- streamEvent.googleGenAIMetadata = extractGenerateContentMetadata(params);
13467
- streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
13686
+ if (this.promptDepth > 0) {
13687
+ return;
13688
+ }
13689
+ const message = event.arguments[0];
13690
+ const sendOptions = event.arguments[1];
13691
+ const agent = event.agent;
13692
+ const metadata = {
13693
+ ...extractSendMetadata(sendOptions),
13694
+ ...agent ? extractAgentMetadata(agent) : {},
13695
+ "cursor_sdk.operation": "agent.send",
13696
+ provider: "cursor",
13697
+ ...event.moduleVersion ? { "cursor_sdk.version": event.moduleVersion } : {}
13698
+ };
13699
+ const span = startSpan({
13700
+ name: "Cursor Agent",
13701
+ spanAttributes: { type: "task" /* TASK */ }
13702
+ });
13703
+ const startTime = getCurrentUnixTimestamp();
13704
+ safeLog(span, {
13705
+ input: sanitizeUserMessage(message),
13706
+ metadata
13707
+ });
13708
+ const state = {
13709
+ activeToolSpans: /* @__PURE__ */ new Map(),
13710
+ agent,
13711
+ conversationText: [],
13712
+ deltaText: [],
13713
+ finalized: false,
13714
+ input: message,
13715
+ metadata,
13716
+ metrics: {},
13717
+ span,
13718
+ startTime,
13719
+ streamMessages: [],
13720
+ streamText: [],
13721
+ stepText: [],
13722
+ taskText: []
13723
+ };
13724
+ if (hasCursorCallbacks(sendOptions)) {
13725
+ event.arguments[1] = wrapSendOptionsCallbacks(sendOptions, state);
13726
+ }
13727
+ states.set(event, state);
13468
13728
  },
13469
13729
  asyncEnd: (event) => {
13470
- const streamEvent = event;
13471
- patchGoogleGenAIStreamingResult({
13472
- input: streamEvent.googleGenAIInput,
13730
+ const state = states.get(event);
13731
+ if (!state) {
13732
+ return;
13733
+ }
13734
+ if (!event.result) {
13735
+ return;
13736
+ }
13737
+ state.run = event.result;
13738
+ state.metadata = {
13739
+ ...state.metadata,
13740
+ ...extractRunMetadata(event.result)
13741
+ };
13742
+ patchCursorRun(event.result, state);
13743
+ },
13744
+ error: (event) => {
13745
+ const state = states.get(event);
13746
+ if (!state || !event.error) {
13747
+ return;
13748
+ }
13749
+ safeLog(state.span, { error: event.error.message });
13750
+ endOpenToolSpans(state, event.error.message);
13751
+ state.span.end();
13752
+ state.finalized = true;
13753
+ states.delete(event);
13754
+ }
13755
+ };
13756
+ channel2.subscribe(handlers);
13757
+ this.unsubscribers.push(() => {
13758
+ channel2.unsubscribe(handlers);
13759
+ });
13760
+ }
13761
+ };
13762
+ function patchCursorAgentInPlace(agent) {
13763
+ if (!agent || typeof agent !== "object") {
13764
+ return;
13765
+ }
13766
+ const agentRecord = agent;
13767
+ if (agentRecord[PATCHED_AGENT] || agentRecord[WRAPPED_AGENT] || typeof agentRecord.send !== "function") {
13768
+ return;
13769
+ }
13770
+ const originalSend = agentRecord.send.bind(agentRecord);
13771
+ try {
13772
+ Object.defineProperty(agentRecord, PATCHED_AGENT, {
13773
+ configurable: false,
13774
+ enumerable: false,
13775
+ value: true
13776
+ });
13777
+ Object.defineProperty(agentRecord, "send", {
13778
+ configurable: true,
13779
+ value(message, options) {
13780
+ const args = [message, options];
13781
+ return cursorSDKChannels.send.tracePromise(
13782
+ () => originalSend(...args),
13783
+ {
13784
+ agent: agentRecord,
13785
+ arguments: args,
13786
+ operation: "send"
13787
+ }
13788
+ );
13789
+ },
13790
+ writable: true
13791
+ });
13792
+ } catch {
13793
+ }
13794
+ }
13795
+ function wrapSendOptionsCallbacks(options, state) {
13796
+ const originalOnDelta = options.onDelta;
13797
+ const originalOnStep = options.onStep;
13798
+ return {
13799
+ ...options,
13800
+ async onDelta(args) {
13801
+ try {
13802
+ await handleInteractionUpdate(state, args.update);
13803
+ } catch (error) {
13804
+ logInstrumentationError("Cursor SDK onDelta", error);
13805
+ }
13806
+ if (originalOnDelta) {
13807
+ return originalOnDelta(args);
13808
+ }
13809
+ },
13810
+ async onStep(args) {
13811
+ try {
13812
+ handleStepUpdate(state, args.step);
13813
+ } catch (error) {
13814
+ logInstrumentationError("Cursor SDK onStep", error);
13815
+ }
13816
+ if (originalOnStep) {
13817
+ return originalOnStep(args);
13818
+ }
13819
+ }
13820
+ };
13821
+ }
13822
+ function hasCursorCallbacks(options) {
13823
+ return !!options && (typeof options.onDelta === "function" || typeof options.onStep === "function");
13824
+ }
13825
+ function patchCursorRun(run, state) {
13826
+ if (!run || typeof run !== "object") {
13827
+ return;
13828
+ }
13829
+ const runRecord = run;
13830
+ if (runRecord[PATCHED_RUN]) {
13831
+ return;
13832
+ }
13833
+ try {
13834
+ Object.defineProperty(runRecord, PATCHED_RUN, {
13835
+ configurable: false,
13836
+ enumerable: false,
13837
+ value: true
13838
+ });
13839
+ if (typeof runRecord.stream === "function") {
13840
+ const originalStream = runRecord.stream.bind(runRecord);
13841
+ Object.defineProperty(runRecord, "stream", {
13842
+ configurable: true,
13843
+ value() {
13844
+ const stream = originalStream();
13845
+ return patchCursorStream(stream, state);
13846
+ },
13847
+ writable: true
13848
+ });
13849
+ }
13850
+ if (typeof runRecord.wait === "function") {
13851
+ const originalWait = runRecord.wait.bind(runRecord);
13852
+ Object.defineProperty(runRecord, "wait", {
13853
+ configurable: true,
13854
+ async value() {
13855
+ try {
13856
+ const result = await originalWait();
13857
+ state.lastResult = result;
13858
+ await finalizeCursorRun(state, { result });
13859
+ return result;
13860
+ } catch (error) {
13861
+ await finalizeCursorRun(state, { error });
13862
+ throw error;
13863
+ }
13864
+ },
13865
+ writable: true
13866
+ });
13867
+ }
13868
+ if (typeof runRecord.conversation === "function") {
13869
+ const originalConversation = runRecord.conversation.bind(runRecord);
13870
+ Object.defineProperty(runRecord, "conversation", {
13871
+ configurable: true,
13872
+ async value() {
13873
+ try {
13874
+ const conversation = await originalConversation();
13875
+ await handleConversation(state, conversation);
13876
+ await finalizeCursorRun(state);
13877
+ return conversation;
13878
+ } catch (error) {
13879
+ await finalizeCursorRun(state, { error });
13880
+ throw error;
13881
+ }
13882
+ },
13883
+ writable: true
13884
+ });
13885
+ }
13886
+ } catch {
13887
+ void finalizeCursorRun(state, { output: run });
13888
+ }
13889
+ }
13890
+ async function* patchCursorStream(stream, state) {
13891
+ try {
13892
+ for await (const message of stream) {
13893
+ try {
13894
+ await handleStreamMessage2(state, message);
13895
+ } catch (error) {
13896
+ logInstrumentationError("Cursor SDK stream", error);
13897
+ }
13898
+ yield message;
13899
+ }
13900
+ await finalizeCursorRun(state);
13901
+ } catch (error) {
13902
+ await finalizeCursorRun(state, { error });
13903
+ throw error;
13904
+ }
13905
+ }
13906
+ async function handleInteractionUpdate(state, update) {
13907
+ switch (update.type) {
13908
+ case "text-delta":
13909
+ if (typeof update.text === "string") {
13910
+ state.deltaText.push(update.text);
13911
+ }
13912
+ return;
13913
+ case "token-delta":
13914
+ if (typeof update.tokens === "number") {
13915
+ state.metrics["cursor_sdk.delta_tokens"] = (state.metrics["cursor_sdk.delta_tokens"] ?? 0) + update.tokens;
13916
+ }
13917
+ return;
13918
+ case "tool-call-started":
13919
+ case "partial-tool-call":
13920
+ case "tool-call-completed":
13921
+ await handleToolUpdate(
13922
+ state,
13923
+ update
13924
+ );
13925
+ return;
13926
+ case "turn-ended":
13927
+ addUsageMetrics(
13928
+ state.metrics,
13929
+ update.usage
13930
+ );
13931
+ return;
13932
+ case "summary":
13933
+ if (typeof update.summary === "string") {
13934
+ state.taskText.push(update.summary);
13935
+ }
13936
+ return;
13937
+ case "step-completed":
13938
+ if (typeof update.stepDurationMs === "number") {
13939
+ state.metrics["cursor_sdk.step_duration_ms"] = (state.metrics["cursor_sdk.step_duration_ms"] ?? 0) + update.stepDurationMs;
13940
+ }
13941
+ state.metrics["cursor_sdk.steps"] = (state.metrics["cursor_sdk.steps"] ?? 0) + 1;
13942
+ return;
13943
+ default:
13944
+ return;
13945
+ }
13946
+ }
13947
+ async function handleToolUpdate(state, update) {
13948
+ const callId = update.callId;
13949
+ if (!callId) {
13950
+ return;
13951
+ }
13952
+ const toolCall = update.toolCall;
13953
+ const name = extractToolName(toolCall);
13954
+ const args = extractToolArgs(toolCall);
13955
+ const result = extractToolResult(toolCall);
13956
+ if (update.type === "tool-call-started" || update.type === "partial-tool-call") {
13957
+ if (!state.activeToolSpans.has(callId)) {
13958
+ state.activeToolSpans.set(
13959
+ callId,
13960
+ await startToolSpan(state, {
13961
+ args,
13962
+ callId,
13963
+ name,
13964
+ status: "running",
13965
+ toolCall
13966
+ })
13967
+ );
13968
+ }
13969
+ return;
13970
+ }
13971
+ const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan(state, {
13972
+ args,
13973
+ callId,
13974
+ name,
13975
+ status: "completed",
13976
+ toolCall
13977
+ });
13978
+ finishToolSpan(toolState, {
13979
+ error: toolCall?.status === "error" ? stringifyUnknown(result) : void 0,
13980
+ metadata: {
13981
+ "cursor_sdk.tool.status": toolCall?.status ?? "completed"
13982
+ },
13983
+ output: result
13984
+ });
13985
+ state.activeToolSpans.delete(callId);
13986
+ }
13987
+ async function handleStreamMessage2(state, message) {
13988
+ state.streamMessages.push(message);
13989
+ if (message.type === "system") {
13990
+ const systemMessage = message;
13991
+ state.metadata = {
13992
+ ...state.metadata,
13993
+ ...extractModelMetadata(systemMessage.model),
13994
+ ...systemMessage.agent_id ? { "cursor_sdk.agent_id": systemMessage.agent_id } : {},
13995
+ ...systemMessage.run_id ? { "cursor_sdk.run_id": systemMessage.run_id } : {},
13996
+ ...systemMessage.tools ? { "cursor_sdk.tools": systemMessage.tools } : {}
13997
+ };
13998
+ return;
13999
+ }
14000
+ if (message.type === "assistant") {
14001
+ const assistantMessage = message;
14002
+ for (const block of assistantMessage.message?.content ?? []) {
14003
+ if (block?.type === "text" && typeof block.text === "string") {
14004
+ state.streamText.push(block.text);
14005
+ } else if (block?.type === "tool_use" && block.id) {
14006
+ state.activeToolSpans.set(
14007
+ block.id,
14008
+ await startToolSpan(state, {
14009
+ args: block.input,
14010
+ callId: block.id,
14011
+ name: block.name,
14012
+ status: "running"
14013
+ })
14014
+ );
14015
+ }
14016
+ }
14017
+ return;
14018
+ }
14019
+ if (message.type === "tool_call") {
14020
+ await handleToolMessage(
14021
+ state,
14022
+ message
14023
+ );
14024
+ return;
14025
+ }
14026
+ if (message.type === "task" && typeof message.text === "string") {
14027
+ state.taskText.push(message.text);
14028
+ return;
14029
+ }
14030
+ if (message.type === "status" && message.status) {
14031
+ state.metadata["cursor_sdk.status"] = message.status;
14032
+ }
14033
+ }
14034
+ async function handleToolMessage(state, message) {
14035
+ const callId = message.call_id;
14036
+ if (!callId) {
14037
+ return;
14038
+ }
14039
+ if (message.status === "running") {
14040
+ if (!state.activeToolSpans.has(callId)) {
14041
+ state.activeToolSpans.set(
14042
+ callId,
14043
+ await startToolSpan(state, {
14044
+ args: message.args,
14045
+ callId,
14046
+ name: message.name,
14047
+ status: message.status,
14048
+ truncated: message.truncated
14049
+ })
14050
+ );
14051
+ }
14052
+ return;
14053
+ }
14054
+ const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan(state, {
14055
+ args: message.args,
14056
+ callId,
14057
+ name: message.name,
14058
+ status: message.status,
14059
+ truncated: message.truncated
14060
+ });
14061
+ finishToolSpan(toolState, {
14062
+ error: message.status === "error" ? stringifyUnknown(message.result) : void 0,
14063
+ metadata: {
14064
+ "cursor_sdk.tool.status": message.status
14065
+ },
14066
+ output: message.result
14067
+ });
14068
+ state.activeToolSpans.delete(callId);
14069
+ }
14070
+ async function handleConversation(state, turns) {
14071
+ state.conversationOutput = turns;
14072
+ for (const turn of turns) {
14073
+ if (turn.type === "agentConversationTurn") {
14074
+ for (const step of turn.turn?.steps ?? []) {
14075
+ await handleConversationStep(state, step);
14076
+ }
14077
+ } else if (turn.type === "shellConversationTurn") {
14078
+ const command = turn.turn?.shellCommand?.command;
14079
+ if (command) {
14080
+ const callId = `shell:${state.activeToolSpans.size}:${command}`;
14081
+ const toolState = await startToolSpan(state, {
14082
+ args: turn.turn?.shellCommand,
14083
+ callId,
14084
+ name: "shell",
14085
+ status: "completed"
14086
+ });
14087
+ finishToolSpan(toolState, {
14088
+ metadata: { "cursor_sdk.tool.status": "completed" },
14089
+ output: turn.turn?.shellOutput
14090
+ });
14091
+ }
14092
+ }
14093
+ }
14094
+ }
14095
+ async function handleConversationStep(state, step) {
14096
+ if (step.type === "assistantMessage" && typeof step.message?.text === "string") {
14097
+ state.conversationText.push(step.message.text);
14098
+ return;
14099
+ }
14100
+ if (step.type !== "toolCall") {
14101
+ return;
14102
+ }
14103
+ const toolCall = step.message;
14104
+ const callId = typeof toolCall?.callId === "string" ? toolCall.callId : `conversation-tool:${state.activeToolSpans.size}`;
14105
+ const toolState = await startToolSpan(state, {
14106
+ args: extractToolArgs(toolCall),
14107
+ callId,
14108
+ name: extractToolName(toolCall),
14109
+ status: toolCall?.status,
14110
+ toolCall
14111
+ });
14112
+ finishToolSpan(toolState, {
14113
+ error: toolCall?.status === "error" ? stringifyUnknown(toolCall.result) : void 0,
14114
+ metadata: {
14115
+ "cursor_sdk.tool.status": toolCall?.status ?? "completed"
14116
+ },
14117
+ output: extractToolResult(toolCall)
14118
+ });
14119
+ }
14120
+ function handleStepUpdate(state, step) {
14121
+ state.metrics["cursor_sdk.steps"] = (state.metrics["cursor_sdk.steps"] ?? 0) + 1;
14122
+ if (step.type) {
14123
+ const stepTypes = state.metadata["cursor_sdk.step_types"];
14124
+ if (Array.isArray(stepTypes)) {
14125
+ if (!stepTypes.includes(step.type)) {
14126
+ stepTypes.push(step.type);
14127
+ }
14128
+ } else {
14129
+ state.metadata["cursor_sdk.step_types"] = [step.type];
14130
+ }
14131
+ }
14132
+ if (step.type === "assistantMessage" && typeof step.message?.text === "string") {
14133
+ state.stepText.push(step.message.text);
14134
+ }
14135
+ }
14136
+ async function startToolSpan(state, args) {
14137
+ const name = args.name || "unknown";
14138
+ const metadata = {
14139
+ "cursor_sdk.tool.status": args.status,
14140
+ "gen_ai.tool.call.id": args.callId,
14141
+ "gen_ai.tool.name": name
14142
+ };
14143
+ if (args.truncated?.args !== void 0) {
14144
+ metadata["cursor_sdk.tool.args_truncated"] = args.truncated.args;
14145
+ }
14146
+ if (args.truncated?.result !== void 0) {
14147
+ metadata["cursor_sdk.tool.result_truncated"] = args.truncated.result;
14148
+ }
14149
+ const span = startSpan({
14150
+ event: {
14151
+ input: args.args,
14152
+ metadata
14153
+ },
14154
+ name: `tool: ${name}`,
14155
+ parent: await state.span.export(),
14156
+ spanAttributes: { type: "tool" /* TOOL */ }
14157
+ });
14158
+ let subAgentSpan;
14159
+ if (isSubAgentToolName(name)) {
14160
+ subAgentSpan = startSpan({
14161
+ event: {
14162
+ input: args.args,
14163
+ metadata: {
14164
+ "cursor_sdk.subagent.tool_call_id": args.callId,
14165
+ "gen_ai.tool.name": name
14166
+ }
14167
+ },
14168
+ name: formatSubAgentSpanName2(args.toolCall, args.args),
14169
+ parent: await span.export(),
14170
+ spanAttributes: { type: "task" /* TASK */ }
14171
+ });
14172
+ }
14173
+ return { span, subAgentSpan };
14174
+ }
14175
+ function finishToolSpan(toolState, result) {
14176
+ try {
14177
+ if (result.error) {
14178
+ safeLog(toolState.span, {
14179
+ error: result.error,
14180
+ metadata: result.metadata,
14181
+ output: result.output
14182
+ });
14183
+ if (toolState.subAgentSpan) {
14184
+ safeLog(toolState.subAgentSpan, {
14185
+ error: result.error,
14186
+ metadata: result.metadata,
14187
+ output: result.output
14188
+ });
14189
+ }
14190
+ } else {
14191
+ safeLog(toolState.span, {
14192
+ metadata: result.metadata,
14193
+ output: result.output
14194
+ });
14195
+ if (toolState.subAgentSpan) {
14196
+ safeLog(toolState.subAgentSpan, {
14197
+ metadata: result.metadata,
14198
+ output: result.output
14199
+ });
14200
+ }
14201
+ }
14202
+ } finally {
14203
+ toolState.subAgentSpan?.end();
14204
+ toolState.span.end();
14205
+ }
14206
+ }
14207
+ async function finalizeCursorRun(state, params = {}) {
14208
+ if (state.finalized) {
14209
+ return;
14210
+ }
14211
+ state.finalized = true;
14212
+ const error = params.error;
14213
+ const result = params.result ?? state.lastResult;
14214
+ const output = params.output ?? result?.result ?? state.run?.result ?? (state.conversationText.length > 0 ? state.conversationText.join("\n") : void 0) ?? state.conversationOutput ?? (state.streamText.length > 0 ? state.streamText.join("") : void 0) ?? (state.deltaText.length > 0 ? state.deltaText.join("") : void 0) ?? (state.stepText.length > 0 ? state.stepText.join("\n") : void 0) ?? (state.taskText.length > 0 ? state.taskText.join("\n") : void 0);
14215
+ try {
14216
+ const metadata = {
14217
+ ...state.metadata,
14218
+ ...state.run ? extractRunMetadata(state.run) : {},
14219
+ ...result ? extractRunResultMetadata(result) : {}
14220
+ };
14221
+ if (error) {
14222
+ safeLog(state.span, {
14223
+ error: error instanceof Error ? error.message : String(error),
14224
+ metadata,
14225
+ metrics: {
14226
+ ...cleanMetrics(state.metrics),
14227
+ ...buildDurationMetrics(state.startTime)
14228
+ },
14229
+ output
14230
+ });
14231
+ } else {
14232
+ safeLog(state.span, {
14233
+ metadata,
14234
+ metrics: {
14235
+ ...cleanMetrics(state.metrics),
14236
+ ...buildDurationMetrics(state.startTime)
14237
+ },
14238
+ output
14239
+ });
14240
+ }
14241
+ } finally {
14242
+ endOpenToolSpans(state);
14243
+ state.span.end();
14244
+ }
14245
+ }
14246
+ function endOpenToolSpans(state, error) {
14247
+ for (const [, toolState] of state.activeToolSpans) {
14248
+ finishToolSpan(toolState, { error });
14249
+ }
14250
+ state.activeToolSpans.clear();
14251
+ }
14252
+ function sanitizeUserMessage(message) {
14253
+ if (typeof message === "string" || message === void 0) {
14254
+ return message;
14255
+ }
14256
+ return {
14257
+ ...message,
14258
+ images: message.images?.map((image) => {
14259
+ const imageRecord = image;
14260
+ return {
14261
+ ...typeof imageRecord.url === "string" ? { url: imageRecord.url } : {},
14262
+ ...typeof imageRecord.mimeType === "string" ? { mimeType: imageRecord.mimeType } : {},
14263
+ ...image.dimension ? { dimension: image.dimension } : {},
14264
+ hasData: typeof imageRecord.data === "string"
14265
+ };
14266
+ })
14267
+ };
14268
+ }
14269
+ function extractAgentOptionsMetadata(options) {
14270
+ if (!options) {
14271
+ return {};
14272
+ }
14273
+ return {
14274
+ ...extractModelMetadata(options.model),
14275
+ ...options.agentId ? { "cursor_sdk.agent_id": options.agentId } : {},
14276
+ ...options.name ? { "cursor_sdk.agent_name": options.name } : {},
14277
+ ...options.local ? {
14278
+ "cursor_sdk.runtime": "local",
14279
+ "cursor_sdk.local.cwd": Array.isArray(options.local.cwd) ? options.local.cwd.join(",") : options.local.cwd
14280
+ } : {},
14281
+ ...options.cloud ? {
14282
+ "cursor_sdk.runtime": "cloud",
14283
+ "cursor_sdk.cloud.auto_create_pr": options.cloud.autoCreatePR,
14284
+ "cursor_sdk.cloud.env_type": options.cloud.env?.type,
14285
+ "cursor_sdk.cloud.env_name": options.cloud.env?.name,
14286
+ "cursor_sdk.cloud.repos": options.cloud.repos?.map((repo) => repo.url).filter((url) => typeof url === "string")
14287
+ } : {}
14288
+ };
14289
+ }
14290
+ function extractSendMetadata(options) {
14291
+ if (!options) {
14292
+ return {};
14293
+ }
14294
+ return {
14295
+ ...extractModelMetadata(options.model),
14296
+ ...options.local?.force !== void 0 ? { "cursor_sdk.local.force": options.local.force } : {}
14297
+ };
14298
+ }
14299
+ function extractAgentMetadata(agent) {
14300
+ return {
14301
+ ...agent.agentId ? { "cursor_sdk.agent_id": agent.agentId } : {},
14302
+ ...extractModelMetadata(agent.model)
14303
+ };
14304
+ }
14305
+ function extractRunMetadata(run) {
14306
+ if (!run) {
14307
+ return {};
14308
+ }
14309
+ return {
14310
+ ...run.id ? { "cursor_sdk.run_id": run.id } : {},
14311
+ ...run.agentId ? { "cursor_sdk.agent_id": run.agentId } : {},
14312
+ ...run.status ? { "cursor_sdk.status": run.status } : {},
14313
+ ...run.durationMs !== void 0 ? { "cursor_sdk.duration_ms": run.durationMs } : {},
14314
+ ...extractModelMetadata(run.model),
14315
+ ...extractGitMetadata(run.git)
14316
+ };
14317
+ }
14318
+ function extractRunResultMetadata(result) {
14319
+ if (!result) {
14320
+ return {};
14321
+ }
14322
+ return {
14323
+ ...result.id ? { "cursor_sdk.run_id": result.id } : {},
14324
+ ...result.status ? { "cursor_sdk.status": result.status } : {},
14325
+ ...result.durationMs !== void 0 ? { "cursor_sdk.duration_ms": result.durationMs } : {},
14326
+ ...extractModelMetadata(result.model),
14327
+ ...extractGitMetadata(result.git)
14328
+ };
14329
+ }
14330
+ function extractGitMetadata(git) {
14331
+ const branches = git?.branches;
14332
+ if (!branches || branches.length === 0) {
14333
+ return {};
14334
+ }
14335
+ return {
14336
+ "cursor_sdk.git.branches": branches.map((branch) => ({
14337
+ branch: branch.branch,
14338
+ prUrl: branch.prUrl,
14339
+ repoUrl: branch.repoUrl
14340
+ }))
14341
+ };
14342
+ }
14343
+ function extractModelMetadata(model) {
14344
+ if (!model?.id) {
14345
+ return {};
14346
+ }
14347
+ return {
14348
+ model: model.id,
14349
+ "cursor_sdk.model": model.id,
14350
+ ...model.params ? { "cursor_sdk.model.params": model.params } : {}
14351
+ };
14352
+ }
14353
+ function addUsageMetrics(metrics, usage) {
14354
+ if (!usage) {
14355
+ return;
14356
+ }
14357
+ if (usage.inputTokens !== void 0) {
14358
+ metrics.prompt_tokens = (metrics.prompt_tokens ?? 0) + usage.inputTokens;
14359
+ }
14360
+ if (usage.outputTokens !== void 0) {
14361
+ metrics.completion_tokens = (metrics.completion_tokens ?? 0) + usage.outputTokens;
14362
+ }
14363
+ if (usage.cacheReadTokens !== void 0) {
14364
+ metrics.prompt_cached_tokens = (metrics.prompt_cached_tokens ?? 0) + usage.cacheReadTokens;
14365
+ }
14366
+ if (usage.cacheWriteTokens !== void 0) {
14367
+ metrics.prompt_cache_creation_tokens = (metrics.prompt_cache_creation_tokens ?? 0) + usage.cacheWriteTokens;
14368
+ }
14369
+ metrics.tokens = (metrics.prompt_tokens ?? 0) + (metrics.completion_tokens ?? 0) + (metrics.prompt_cached_tokens ?? 0) + (metrics.prompt_cache_creation_tokens ?? 0);
14370
+ }
14371
+ function buildDurationMetrics(startTime) {
14372
+ const end = getCurrentUnixTimestamp();
14373
+ return {
14374
+ duration: end - startTime,
14375
+ end,
14376
+ start: startTime
14377
+ };
14378
+ }
14379
+ function extractToolName(toolCall) {
14380
+ if (!toolCall) {
14381
+ return "unknown";
14382
+ }
14383
+ if (typeof toolCall.name === "string") {
14384
+ return toolCall.name;
14385
+ }
14386
+ if (typeof toolCall.type === "string") {
14387
+ return toolCall.type;
14388
+ }
14389
+ return "unknown";
14390
+ }
14391
+ function extractToolArgs(toolCall) {
14392
+ return toolCall && "args" in toolCall ? toolCall.args : void 0;
14393
+ }
14394
+ function extractToolResult(toolCall) {
14395
+ return toolCall && "result" in toolCall ? toolCall.result : void 0;
14396
+ }
14397
+ function isSubAgentToolName(name) {
14398
+ return name === "Agent" || name === "Task" || name === "task";
14399
+ }
14400
+ function formatSubAgentSpanName2(toolCall, args) {
14401
+ const details = toolCall ?? args;
14402
+ const description = getString(details, "description") ?? getString(details, "subagent_type") ?? getString(details, "type") ?? getString(details, "name");
14403
+ return description ? `Agent: ${description}` : "Agent: sub-agent";
14404
+ }
14405
+ function getString(obj, key) {
14406
+ const value = obj?.[key];
14407
+ return typeof value === "string" ? value : void 0;
14408
+ }
14409
+ function stringifyUnknown(value) {
14410
+ if (value instanceof Error) {
14411
+ return value.message;
14412
+ }
14413
+ if (typeof value === "string") {
14414
+ return value;
14415
+ }
14416
+ try {
14417
+ return JSON.stringify(value);
14418
+ } catch {
14419
+ return String(value);
14420
+ }
14421
+ }
14422
+ function safeLog(span, event) {
14423
+ try {
14424
+ span.log(event);
14425
+ } catch (error) {
14426
+ logInstrumentationError("Cursor SDK span log", error);
14427
+ }
14428
+ }
14429
+ function logInstrumentationError(context, error) {
14430
+ debugLogger.error(`Error processing ${context}:`, error);
14431
+ }
14432
+ function cleanMetrics(metrics) {
14433
+ const cleaned = {};
14434
+ for (const [key, value] of Object.entries(metrics)) {
14435
+ if (value !== void 0 && Number.isFinite(value)) {
14436
+ cleaned[key] = value;
14437
+ }
14438
+ }
14439
+ return cleaned;
14440
+ }
14441
+
14442
+ // src/instrumentation/plugins/google-genai-channels.ts
14443
+ var googleGenAIChannels = defineChannels("@google/genai", {
14444
+ generateContent: channel({
14445
+ channelName: "models.generateContent",
14446
+ kind: "async"
14447
+ }),
14448
+ generateContentStream: channel({
14449
+ channelName: "models.generateContentStream",
14450
+ kind: "async"
14451
+ }),
14452
+ embedContent: channel({
14453
+ channelName: "models.embedContent",
14454
+ kind: "async"
14455
+ })
14456
+ });
14457
+
14458
+ // src/instrumentation/plugins/google-genai-plugin.ts
14459
+ var GOOGLE_GENAI_INTERNAL_CONTEXT = {
14460
+ caller_filename: "<node-internal>",
14461
+ caller_functionname: "<node-internal>",
14462
+ caller_lineno: 0
14463
+ };
14464
+ function createWrapperParityEvent(args) {
14465
+ return {
14466
+ context: GOOGLE_GENAI_INTERNAL_CONTEXT,
14467
+ input: args.input,
14468
+ metadata: args.metadata
14469
+ };
14470
+ }
14471
+ var GoogleGenAIPlugin = class extends BasePlugin {
14472
+ onEnable() {
14473
+ this.subscribeToGoogleGenAIChannels();
14474
+ }
14475
+ onDisable() {
14476
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
14477
+ }
14478
+ subscribeToGoogleGenAIChannels() {
14479
+ this.subscribeToGenerateContentChannel();
14480
+ this.subscribeToGenerateContentStreamChannel();
14481
+ this.subscribeToEmbedContentChannel();
14482
+ }
14483
+ subscribeToGenerateContentChannel() {
14484
+ const tracingChannel = googleGenAIChannels.generateContent.tracingChannel();
14485
+ const states = /* @__PURE__ */ new WeakMap();
14486
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
14487
+ tracingChannel,
14488
+ states,
14489
+ (event) => {
14490
+ const params = event.arguments[0];
14491
+ const input = serializeGenerateContentInput(params);
14492
+ const metadata = extractGenerateContentMetadata(params);
14493
+ const span = startSpan({
14494
+ name: "generate_content",
14495
+ spanAttributes: {
14496
+ type: "llm" /* LLM */
14497
+ },
14498
+ event: createWrapperParityEvent({ input, metadata })
14499
+ });
14500
+ return {
14501
+ span,
14502
+ startTime: getCurrentUnixTimestamp()
14503
+ };
14504
+ }
14505
+ );
14506
+ const handlers = {
14507
+ start: (event) => {
14508
+ ensureSpanState(states, event, () => {
14509
+ const params = event.arguments[0];
14510
+ const input = serializeGenerateContentInput(params);
14511
+ const metadata = extractGenerateContentMetadata(params);
14512
+ const span = startSpan({
14513
+ name: "generate_content",
14514
+ spanAttributes: {
14515
+ type: "llm" /* LLM */
14516
+ },
14517
+ event: createWrapperParityEvent({ input, metadata })
14518
+ });
14519
+ return {
14520
+ span,
14521
+ startTime: getCurrentUnixTimestamp()
14522
+ };
14523
+ });
14524
+ },
14525
+ asyncEnd: (event) => {
14526
+ const spanState = states.get(event);
14527
+ if (!spanState) {
14528
+ return;
14529
+ }
14530
+ try {
14531
+ const responseMetadata = extractResponseMetadata(event.result);
14532
+ spanState.span.log({
14533
+ ...responseMetadata ? { metadata: responseMetadata } : {},
14534
+ metrics: cleanMetrics2(
14535
+ extractGenerateContentMetrics(
14536
+ event.result,
14537
+ spanState.startTime
14538
+ )
14539
+ ),
14540
+ output: event.result
14541
+ });
14542
+ } finally {
14543
+ spanState.span.end();
14544
+ states.delete(event);
14545
+ }
14546
+ },
14547
+ error: (event) => {
14548
+ logErrorAndEndSpan(states, event);
14549
+ }
14550
+ };
14551
+ tracingChannel.subscribe(handlers);
14552
+ this.unsubscribers.push(() => {
14553
+ unbindCurrentSpanStore?.();
14554
+ tracingChannel.unsubscribe(handlers);
14555
+ });
14556
+ }
14557
+ subscribeToGenerateContentStreamChannel() {
14558
+ const tracingChannel = googleGenAIChannels.generateContentStream.tracingChannel();
14559
+ const handlers = {
14560
+ start: (event) => {
14561
+ const streamEvent = event;
14562
+ const params = event.arguments[0];
14563
+ streamEvent.googleGenAIInput = serializeGenerateContentInput(params);
14564
+ streamEvent.googleGenAIMetadata = extractGenerateContentMetadata(params);
14565
+ streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
14566
+ },
14567
+ asyncEnd: (event) => {
14568
+ const streamEvent = event;
14569
+ patchGoogleGenAIStreamingResult({
14570
+ input: streamEvent.googleGenAIInput,
13473
14571
  metadata: streamEvent.googleGenAIMetadata,
13474
14572
  startTime: streamEvent.googleGenAIStartTime,
13475
14573
  result: streamEvent.result
@@ -13534,7 +14632,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
13534
14632
  const output = summarizeEmbedContentOutput(event.result);
13535
14633
  spanState.span.log({
13536
14634
  ...output ? { output } : {},
13537
- metrics: cleanMetrics(
14635
+ metrics: cleanMetrics2(
13538
14636
  extractEmbedContentMetrics(event.result, spanState.startTime)
13539
14637
  )
13540
14638
  });
@@ -13631,7 +14729,7 @@ function patchGoogleGenAIStreamingResult(args) {
13631
14729
  );
13632
14730
  span.log({
13633
14731
  ...responseMetadata ? { metadata: responseMetadata } : {},
13634
- metrics: cleanMetrics(metricsWithoutEnd),
14732
+ metrics: cleanMetrics2(metricsWithoutEnd),
13635
14733
  output: options.result.aggregated
13636
14734
  });
13637
14735
  span.end(typeof end === "number" ? { endTime: end } : void 0);
@@ -14056,7 +15154,7 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
14056
15154
  }
14057
15155
  return { aggregated, metrics };
14058
15156
  }
14059
- function cleanMetrics(metrics) {
15157
+ function cleanMetrics2(metrics) {
14060
15158
  const cleaned = {};
14061
15159
  for (const [key, value] of Object.entries(metrics)) {
14062
15160
  if (value !== null && value !== void 0) {
@@ -14140,6 +15238,8 @@ var REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
14140
15238
  "stop",
14141
15239
  "stream",
14142
15240
  "temperature",
15241
+ "tool_choice",
15242
+ "tools",
14143
15243
  "top_p"
14144
15244
  ]);
14145
15245
  var RESPONSE_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
@@ -14402,7 +15502,10 @@ function aggregateChatCompletionChunks2(chunks) {
14402
15502
  for (const chunk of chunks) {
14403
15503
  for (const choice of chunk.choices ?? []) {
14404
15504
  const index = typeof choice.index === "number" ? choice.index : 0;
14405
- const existing = aggregatedChoices.get(index) ?? { content: "" };
15505
+ const existing = aggregatedChoices.get(index) ?? {
15506
+ content: "",
15507
+ toolCallsByIndex: /* @__PURE__ */ new Map()
15508
+ };
14406
15509
  const delta = isObject(choice.delta) ? choice.delta : void 0;
14407
15510
  const message = isObject(choice.message) ? choice.message : void 0;
14408
15511
  if (typeof delta?.content === "string") {
@@ -14418,6 +15521,10 @@ function aggregateChatCompletionChunks2(chunks) {
14418
15521
  if (choice.finish_reason !== void 0) {
14419
15522
  existing.finish_reason = choice.finish_reason;
14420
15523
  }
15524
+ const toolCallDeltas = getChatToolCallDeltas(delta) ?? getChatToolCallDeltas(message);
15525
+ if (toolCallDeltas) {
15526
+ mergeChatToolCallDeltas(existing.toolCallsByIndex, toolCallDeltas);
15527
+ }
14421
15528
  aggregatedChoices.set(index, existing);
14422
15529
  }
14423
15530
  }
@@ -14426,12 +15533,72 @@ function aggregateChatCompletionChunks2(chunks) {
14426
15533
  index,
14427
15534
  message: {
14428
15535
  content: choice.content,
14429
- role: choice.role ?? "assistant"
15536
+ role: choice.role ?? "assistant",
15537
+ ...choice.toolCallsByIndex.size > 0 ? {
15538
+ tool_calls: [...choice.toolCallsByIndex.entries()].sort(([leftIndex], [rightIndex]) => leftIndex - rightIndex).map(([, toolCall]) => toolCall)
15539
+ } : {}
14430
15540
  },
14431
15541
  ...choice.finish_reason !== void 0 ? { finish_reason: choice.finish_reason } : {}
14432
15542
  }))
14433
15543
  };
14434
15544
  }
15545
+ function getChatToolCallDeltas(value) {
15546
+ if (!Array.isArray(value?.tool_calls)) {
15547
+ return void 0;
15548
+ }
15549
+ const toolCalls = value.tool_calls.filter((toolCall) => isObject(toolCall));
15550
+ return toolCalls.length > 0 ? toolCalls : void 0;
15551
+ }
15552
+ function mergeChatToolCallDeltas(toolCallsByIndex, toolCallDeltas) {
15553
+ for (const toolDelta of toolCallDeltas) {
15554
+ const toolIndex = typeof toolDelta.index === "number" && toolDelta.index >= 0 ? toolDelta.index : 0;
15555
+ const existing = toolCallsByIndex.get(toolIndex);
15556
+ if (!existing) {
15557
+ toolCallsByIndex.set(toolIndex, createChatToolCall(toolDelta));
15558
+ continue;
15559
+ }
15560
+ mergeChatToolCall(existing, toolDelta);
15561
+ }
15562
+ }
15563
+ function createChatToolCall(toolDelta) {
15564
+ const toolFunction = isObject(toolDelta.function) ? toolDelta.function : {};
15565
+ const toolCallFunction = {
15566
+ arguments: typeof toolFunction.arguments === "string" ? toolFunction.arguments : ""
15567
+ };
15568
+ if (typeof toolFunction.name === "string") {
15569
+ toolCallFunction.name = toolFunction.name;
15570
+ }
15571
+ const toolCall = {
15572
+ function: toolCallFunction
15573
+ };
15574
+ if (typeof toolDelta.id === "string") {
15575
+ toolCall.id = toolDelta.id;
15576
+ }
15577
+ if (typeof toolDelta.type === "string") {
15578
+ toolCall.type = toolDelta.type;
15579
+ }
15580
+ return toolCall;
15581
+ }
15582
+ function mergeChatToolCall(existing, toolDelta) {
15583
+ const currentFunction = isObject(existing.function) ? existing.function : {};
15584
+ const deltaFunction = isObject(toolDelta.function) ? toolDelta.function : {};
15585
+ const currentArguments = typeof currentFunction.arguments === "string" ? currentFunction.arguments : "";
15586
+ const deltaArguments = typeof deltaFunction.arguments === "string" ? deltaFunction.arguments : "";
15587
+ if (typeof toolDelta.id === "string" && typeof existing.id !== "string") {
15588
+ existing.id = toolDelta.id;
15589
+ }
15590
+ if (typeof toolDelta.type === "string" && typeof existing.type !== "string") {
15591
+ existing.type = toolDelta.type;
15592
+ }
15593
+ const nextFunction = {
15594
+ ...currentFunction,
15595
+ arguments: `${currentArguments}${deltaArguments}`
15596
+ };
15597
+ if (typeof deltaFunction.name === "string" && typeof currentFunction.name !== "string") {
15598
+ nextFunction.name = deltaFunction.name;
15599
+ }
15600
+ existing.function = nextFunction;
15601
+ }
14435
15602
  function aggregateTextGenerationStreamChunks(chunks) {
14436
15603
  if (chunks.length === 0) {
14437
15604
  return void 0;
@@ -16476,6 +17643,8 @@ var MISTRAL_REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
16476
17643
  "presence_penalty",
16477
17644
  "randomSeed",
16478
17645
  "random_seed",
17646
+ "reasoningEffort",
17647
+ "reasoning_effort",
16479
17648
  "responseFormat",
16480
17649
  "response_format",
16481
17650
  "safePrompt",
@@ -16616,6 +17785,98 @@ function extractDeltaText(content) {
16616
17785
  }).filter((part) => part.length > 0);
16617
17786
  return textParts.length > 0 ? textParts.join("") : void 0;
16618
17787
  }
17788
+ function normalizeMistralTextContentPart(part) {
17789
+ if (!isObject(part) || part.type !== "text" || typeof part.text !== "string") {
17790
+ return void 0;
17791
+ }
17792
+ return {
17793
+ type: "text",
17794
+ text: part.text
17795
+ };
17796
+ }
17797
+ function normalizeMistralThinkingContentPart(part) {
17798
+ if (!isObject(part) || part.type !== "thinking") {
17799
+ return void 0;
17800
+ }
17801
+ const thinking = Array.isArray(part.thinking) ? part.thinking.map((thinkingPart) => normalizeMistralTextContentPart(thinkingPart)).filter(
17802
+ (thinkingPart) => thinkingPart !== void 0 && typeof thinkingPart.text === "string"
17803
+ ) : [];
17804
+ return {
17805
+ type: "thinking",
17806
+ thinking
17807
+ };
17808
+ }
17809
+ function normalizeMistralContentParts(content) {
17810
+ if (!Array.isArray(content)) {
17811
+ return [];
17812
+ }
17813
+ return content.map((part) => {
17814
+ return normalizeMistralTextContentPart(part) || normalizeMistralThinkingContentPart(part);
17815
+ }).filter((part) => part !== void 0);
17816
+ }
17817
+ function mergeMistralTextSegments(left, right) {
17818
+ const merged = left.map((part) => ({ ...part }));
17819
+ for (const part of right) {
17820
+ const lastPart = merged[merged.length - 1];
17821
+ if (lastPart && lastPart.type === "text" && typeof lastPart.text === "string" && typeof part.text === "string") {
17822
+ lastPart.text += part.text;
17823
+ continue;
17824
+ }
17825
+ merged.push({ ...part });
17826
+ }
17827
+ return merged;
17828
+ }
17829
+ function mergeMistralContentParts(left, right) {
17830
+ const merged = [...(left || []).map((part) => structuredClone(part))];
17831
+ for (const part of right) {
17832
+ const lastPart = merged[merged.length - 1];
17833
+ if (part.type === "text" && lastPart?.type === "text" && typeof lastPart.text === "string" && typeof part.text === "string") {
17834
+ lastPart.text += part.text;
17835
+ continue;
17836
+ }
17837
+ if (part.type === "thinking" && lastPart?.type === "thinking" && Array.isArray(lastPart.thinking) && Array.isArray(part.thinking)) {
17838
+ lastPart.thinking = mergeMistralTextSegments(
17839
+ lastPart.thinking,
17840
+ part.thinking
17841
+ );
17842
+ continue;
17843
+ }
17844
+ merged.push(structuredClone(part));
17845
+ }
17846
+ return merged;
17847
+ }
17848
+ function appendMistralContent(accumulator, content) {
17849
+ if (typeof content === "string") {
17850
+ if (accumulator.contentParts) {
17851
+ accumulator.contentParts = mergeMistralContentParts(
17852
+ accumulator.contentParts,
17853
+ [{ type: "text", text: content }]
17854
+ );
17855
+ return;
17856
+ }
17857
+ accumulator.content = `${accumulator.content || ""}${content}`;
17858
+ return;
17859
+ }
17860
+ const normalizedContentParts = normalizeMistralContentParts(content);
17861
+ if (normalizedContentParts.length === 0) {
17862
+ return;
17863
+ }
17864
+ const hasStructuredContent = normalizedContentParts.some(
17865
+ (part) => part.type !== "text"
17866
+ );
17867
+ if (!accumulator.contentParts && !hasStructuredContent) {
17868
+ const text = extractDeltaText(content);
17869
+ if (text) {
17870
+ accumulator.content = `${accumulator.content || ""}${text}`;
17871
+ }
17872
+ return;
17873
+ }
17874
+ accumulator.contentParts = mergeMistralContentParts(
17875
+ accumulator.contentParts || (accumulator.content ? [{ type: "text", text: accumulator.content }] : []),
17876
+ normalizedContentParts
17877
+ );
17878
+ delete accumulator.content;
17879
+ }
16619
17880
  function getDeltaToolCalls(delta) {
16620
17881
  const toolCalls = Array.isArray(delta.toolCalls) && delta.toolCalls || Array.isArray(delta.tool_calls) && delta.tool_calls || [];
16621
17882
  return toolCalls.filter((toolCall) => isObject(toolCall));
@@ -16784,10 +18045,7 @@ function aggregateMistralStreamChunks(chunks) {
16784
18045
  if (!accumulator.role && typeof delta.role === "string") {
16785
18046
  accumulator.role = delta.role;
16786
18047
  }
16787
- const deltaText = extractDeltaText(delta.content);
16788
- if (deltaText) {
16789
- accumulator.content = `${accumulator.content || ""}${deltaText}`;
16790
- }
18048
+ appendMistralContent(accumulator, delta.content);
16791
18049
  accumulator.toolCalls = mergeToolCallDeltas(
16792
18050
  accumulator.toolCalls,
16793
18051
  getDeltaToolCalls(delta)
@@ -16805,7 +18063,7 @@ function aggregateMistralStreamChunks(chunks) {
16805
18063
  index: choice.index,
16806
18064
  message: {
16807
18065
  ...choice.role ? { role: choice.role } : {},
16808
- content: choice.content ?? null,
18066
+ content: choice.contentParts ?? choice.content ?? null,
16809
18067
  ...choice.toolCalls ? { toolCalls: choice.toolCalls } : {}
16810
18068
  },
16811
18069
  ...choice.finishReason !== void 0 ? { finishReason: choice.finishReason } : {}
@@ -17044,7 +18302,7 @@ var GoogleADKPlugin = class extends BasePlugin {
17044
18302
  start: (event) => {
17045
18303
  const req = event.arguments[0] ?? {};
17046
18304
  const tool = event.self;
17047
- const toolName = extractToolName(req, tool);
18305
+ const toolName = extractToolName2(req, tool);
17048
18306
  const parentSpan = findToolParentSpan(
17049
18307
  req,
17050
18308
  this.activeAgentSpans,
@@ -17083,7 +18341,7 @@ var GoogleADKPlugin = class extends BasePlugin {
17083
18341
  metrics.duration = end - state.startTime;
17084
18342
  state.span.log({
17085
18343
  output: event.result,
17086
- metrics: cleanMetrics2(metrics)
18344
+ metrics: cleanMetrics3(metrics)
17087
18345
  });
17088
18346
  } finally {
17089
18347
  state.span.end();
@@ -17302,7 +18560,7 @@ function extractToolCallId(req) {
17302
18560
  const toolContext = req.toolContext;
17303
18561
  return toolContext?.functionCallId;
17304
18562
  }
17305
- function extractToolName(req, tool) {
18563
+ function extractToolName2(req, tool) {
17306
18564
  if (typeof tool?.name === "string" && tool.name.length > 0) {
17307
18565
  return tool.name;
17308
18566
  }
@@ -17350,7 +18608,7 @@ function finalizeRunnerSpan(state, activeRunnerSpans) {
17350
18608
  }
17351
18609
  state.span.log({
17352
18610
  output: lastEvent ? extractEventOutput(lastEvent) : void 0,
17353
- metrics: cleanMetrics2(metrics)
18611
+ metrics: cleanMetrics3(metrics)
17354
18612
  });
17355
18613
  } finally {
17356
18614
  cleanupActiveRunnerSpan(state, activeRunnerSpans);
@@ -17367,7 +18625,7 @@ function finalizeAgentSpan(state, activeAgentSpans) {
17367
18625
  metrics.duration = end - state.startTime;
17368
18626
  state.span.log({
17369
18627
  output: lastEvent ? extractEventOutput(lastEvent) : void 0,
17370
- metrics: cleanMetrics2(metrics)
18628
+ metrics: cleanMetrics3(metrics)
17371
18629
  });
17372
18630
  } finally {
17373
18631
  cleanupActiveAgentSpan(state, activeAgentSpans);
@@ -17453,7 +18711,7 @@ function populateUsageMetrics2(metrics, usage) {
17453
18711
  metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
17454
18712
  }
17455
18713
  }
17456
- function cleanMetrics2(metrics) {
18714
+ function cleanMetrics3(metrics) {
17457
18715
  const cleaned = {};
17458
18716
  for (const [key, value] of Object.entries(metrics)) {
17459
18717
  if (value !== null && value !== void 0) {
@@ -17581,6 +18839,11 @@ var CHAT_REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
17581
18839
  "strictTools",
17582
18840
  "strict_tools",
17583
18841
  "temperature",
18842
+ "thinking",
18843
+ "thinkingTokenBudget",
18844
+ "thinkingType",
18845
+ "thinking_token_budget",
18846
+ "thinking_type",
17584
18847
  "toolChoice",
17585
18848
  "tool_choice"
17586
18849
  ]);
@@ -17801,6 +19064,11 @@ function mergeUsageMetrics(metrics, usage) {
17801
19064
  "tokens",
17802
19065
  tokenContainer.totalTokens ?? tokenContainer.total_tokens
17803
19066
  );
19067
+ setMetricIfNumber(
19068
+ metrics,
19069
+ "reasoning_tokens",
19070
+ tokenContainer.reasoningTokens ?? tokenContainer.reasoning_tokens ?? tokenContainer.thinkingTokens ?? tokenContainer.thinking_tokens
19071
+ );
17804
19072
  }
17805
19073
  const billedUnits = (isObject(source.billedUnits) ? source.billedUnits : void 0) || (isObject(source.billed_units) ? source.billed_units : void 0);
17806
19074
  if (billedUnits) {
@@ -17881,13 +19149,87 @@ function extractV8DeltaText(chunk) {
17881
19149
  }
17882
19150
  return void 0;
17883
19151
  }
19152
+ function getV8ContentIndex(chunk) {
19153
+ return typeof chunk.index === "number" ? chunk.index : 0;
19154
+ }
19155
+ function toContentBlockType(value) {
19156
+ return value === "text" || value === "thinking" ? value : void 0;
19157
+ }
19158
+ function getOrCreateContentBlock(contentBlocksByIndex, contentBlockOrder, index) {
19159
+ if (!contentBlockOrder.includes(index)) {
19160
+ contentBlockOrder.push(index);
19161
+ }
19162
+ if (!(index in contentBlocksByIndex)) {
19163
+ contentBlocksByIndex[index] = {
19164
+ text: "",
19165
+ thinking: ""
19166
+ };
19167
+ }
19168
+ return contentBlocksByIndex[index];
19169
+ }
19170
+ function appendV8ContentBlock(contentBlocksByIndex, contentBlockOrder, index, content) {
19171
+ if (typeof content === "string") {
19172
+ const block2 = getOrCreateContentBlock(
19173
+ contentBlocksByIndex,
19174
+ contentBlockOrder,
19175
+ index
19176
+ );
19177
+ block2.type ??= "text";
19178
+ block2.text += content;
19179
+ return;
19180
+ }
19181
+ if (!isObject(content)) {
19182
+ return;
19183
+ }
19184
+ const block = getOrCreateContentBlock(
19185
+ contentBlocksByIndex,
19186
+ contentBlockOrder,
19187
+ index
19188
+ );
19189
+ const contentType = toContentBlockType(content.type);
19190
+ if (contentType) {
19191
+ block.type = contentType;
19192
+ }
19193
+ if (typeof content.text === "string") {
19194
+ block.type ??= "text";
19195
+ block.text += content.text;
19196
+ }
19197
+ if (typeof content.thinking === "string") {
19198
+ block.type ??= "thinking";
19199
+ block.thinking += content.thinking;
19200
+ }
19201
+ }
19202
+ function serializeAggregatedContentBlocks(contentBlocksByIndex, contentBlockOrder) {
19203
+ return contentBlockOrder.sort((left, right) => left - right).flatMap((index) => {
19204
+ const block = contentBlocksByIndex[index];
19205
+ if (!block) {
19206
+ return [];
19207
+ }
19208
+ if (block.type === "thinking" && block.thinking.length > 0) {
19209
+ return [{ type: "thinking", thinking: block.thinking }];
19210
+ }
19211
+ if (block.text.length > 0) {
19212
+ return [{ type: "text", text: block.text }];
19213
+ }
19214
+ if (block.thinking.length > 0) {
19215
+ return [{ type: "thinking", thinking: block.thinking }];
19216
+ }
19217
+ return [];
19218
+ });
19219
+ }
19220
+ function hasThinkingContent(contentBlocks) {
19221
+ return contentBlocks.some((block) => block.type === "thinking");
19222
+ }
17884
19223
  function aggregateCohereChatStreamChunks(chunks) {
17885
19224
  const textDeltas = [];
19225
+ const contentBlocksByIndex = {};
19226
+ const contentBlockOrder = [];
17886
19227
  const toolCallsByIndex = {};
17887
19228
  const toolCallOrder = [];
17888
19229
  let terminalResponse;
17889
19230
  let role;
17890
19231
  let finishReason;
19232
+ let toolPlan = "";
17891
19233
  let metadata = {};
17892
19234
  let metrics = {};
17893
19235
  for (const chunk of chunks) {
@@ -17945,12 +19287,36 @@ function aggregateCohereChatStreamChunks(chunks) {
17945
19287
  continue;
17946
19288
  }
17947
19289
  if (eventType === "content-delta") {
19290
+ appendV8ContentBlock(
19291
+ contentBlocksByIndex,
19292
+ contentBlockOrder,
19293
+ getV8ContentIndex(chunk),
19294
+ isObject(chunk.delta) && isObject(chunk.delta.message) ? chunk.delta.message.content : void 0
19295
+ );
17948
19296
  const text = extractV8DeltaText(chunk);
17949
19297
  if (text) {
17950
19298
  textDeltas.push(text);
17951
19299
  }
17952
19300
  continue;
17953
19301
  }
19302
+ if (eventType === "content-start") {
19303
+ appendV8ContentBlock(
19304
+ contentBlocksByIndex,
19305
+ contentBlockOrder,
19306
+ getV8ContentIndex(chunk),
19307
+ isObject(chunk.delta) && isObject(chunk.delta.message) ? chunk.delta.message.content : void 0
19308
+ );
19309
+ continue;
19310
+ }
19311
+ if (eventType === "tool-plan-delta") {
19312
+ if (isObject(chunk.delta) && isObject(chunk.delta.message)) {
19313
+ const deltaToolPlan = typeof chunk.delta.message.toolPlan === "string" ? chunk.delta.message.toolPlan : typeof chunk.delta.message.tool_plan === "string" ? chunk.delta.message.tool_plan : void 0;
19314
+ if (deltaToolPlan) {
19315
+ toolPlan += deltaToolPlan;
19316
+ }
19317
+ }
19318
+ continue;
19319
+ }
17954
19320
  if (eventType === "tool-call-start") {
17955
19321
  const toolCalls = isObject(chunk.delta) && isObject(chunk.delta.message) ? toToolCallArray(
17956
19322
  Array.isArray(chunk.delta.message.toolCalls) ? chunk.delta.message.toolCalls : chunk.delta.message.toolCalls ?? chunk.delta.message.tool_calls
@@ -18004,13 +19370,26 @@ function aggregateCohereChatStreamChunks(chunks) {
18004
19370
  }
18005
19371
  }
18006
19372
  const mergedToolCalls = toolCallOrder.sort((left, right) => left - right).map((index) => toolCallsByIndex[index]).filter((toolCall) => isObject(toolCall));
19373
+ const aggregatedContentBlocks = serializeAggregatedContentBlocks(
19374
+ contentBlocksByIndex,
19375
+ contentBlockOrder
19376
+ );
18007
19377
  let output = extractCohereChatOutput(terminalResponse);
18008
19378
  if (output === void 0) {
18009
19379
  const mergedText = textDeltas.join("");
18010
- if (mergedToolCalls.length > 0 || role || mergedText.length > 0) {
19380
+ const shouldUseStructuredContent = hasThinkingContent(aggregatedContentBlocks) || toolPlan.length > 0;
19381
+ if (shouldUseStructuredContent) {
19382
+ output = {
19383
+ ...role ? { role } : {},
19384
+ ...aggregatedContentBlocks.length > 0 ? { content: aggregatedContentBlocks } : {},
19385
+ ...toolPlan.length > 0 ? { toolPlan } : {},
19386
+ ...mergedToolCalls.length > 0 ? { toolCalls: mergedToolCalls } : {}
19387
+ };
19388
+ } else if (mergedToolCalls.length > 0 || role || mergedText.length > 0 || aggregatedContentBlocks.length > 0) {
19389
+ const textContent = mergedText.length > 0 ? mergedText : aggregatedContentBlocks[0]?.type === "text" ? aggregatedContentBlocks[0].text : void 0;
18011
19390
  output = {
18012
19391
  ...role ? { role } : {},
18013
- ...mergedText.length > 0 ? { content: mergedText } : {},
19392
+ ...textContent ? { content: textContent } : {},
18014
19393
  ...mergedToolCalls.length > 0 ? { toolCalls: mergedToolCalls } : {}
18015
19394
  };
18016
19395
  }
@@ -18028,6 +19407,98 @@ function aggregateCohereChatStreamChunks(chunks) {
18028
19407
  };
18029
19408
  }
18030
19409
 
19410
+ // src/instrumentation/plugins/groq-channels.ts
19411
+ var groqChannels = defineChannels("groq-sdk", {
19412
+ chatCompletionsCreate: channel({
19413
+ channelName: "chat.completions.create",
19414
+ kind: "async"
19415
+ }),
19416
+ embeddingsCreate: channel(
19417
+ {
19418
+ channelName: "embeddings.create",
19419
+ kind: "async"
19420
+ }
19421
+ )
19422
+ });
19423
+
19424
+ // src/instrumentation/plugins/groq-plugin.ts
19425
+ var GroqPlugin = class extends BasePlugin {
19426
+ onEnable() {
19427
+ this.unsubscribers.push(
19428
+ traceStreamingChannel(groqChannels.chatCompletionsCreate, {
19429
+ name: "groq.chat.completions.create",
19430
+ type: "llm" /* LLM */,
19431
+ extractInput: ([params]) => {
19432
+ const { messages, ...metadata } = params;
19433
+ return {
19434
+ input: processInputAttachments(messages),
19435
+ metadata: { ...metadata, provider: "groq" }
19436
+ };
19437
+ },
19438
+ extractOutput: (result) => result?.choices,
19439
+ extractMetrics: (result, startTime) => {
19440
+ const metrics = parseGroqMetrics(result);
19441
+ if (startTime) {
19442
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
19443
+ }
19444
+ return metrics;
19445
+ },
19446
+ aggregateChunks: aggregateGroqChatCompletionChunks
19447
+ })
19448
+ );
19449
+ this.unsubscribers.push(
19450
+ traceAsyncChannel(groqChannels.embeddingsCreate, {
19451
+ name: "groq.embeddings.create",
19452
+ type: "llm" /* LLM */,
19453
+ extractInput: ([params]) => {
19454
+ const { input, ...metadata } = params;
19455
+ return {
19456
+ input,
19457
+ metadata: { ...metadata, provider: "groq" }
19458
+ };
19459
+ },
19460
+ extractOutput: (result) => {
19461
+ const embedding = result?.data?.[0]?.embedding;
19462
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
19463
+ },
19464
+ extractMetrics: (result) => parseGroqMetrics(result)
19465
+ })
19466
+ );
19467
+ }
19468
+ onDisable() {
19469
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
19470
+ }
19471
+ };
19472
+ function parseGroqMetrics(result) {
19473
+ const metrics = parseMetricsFromUsage(result?.usage);
19474
+ const xGroq = result?.x_groq;
19475
+ if (!xGroq || typeof xGroq !== "object") {
19476
+ return metrics;
19477
+ }
19478
+ const extraUsage = "usage" in xGroq ? xGroq.usage : void 0;
19479
+ if (!extraUsage || typeof extraUsage !== "object") {
19480
+ return metrics;
19481
+ }
19482
+ const dramCachedTokens = extraUsage["dram_cached_tokens"];
19483
+ const sramCachedTokens = extraUsage["sram_cached_tokens"];
19484
+ return {
19485
+ ...metrics,
19486
+ ...typeof dramCachedTokens === "number" ? { dram_cached_tokens: dramCachedTokens } : {},
19487
+ ...typeof sramCachedTokens === "number" ? { sram_cached_tokens: sramCachedTokens } : {}
19488
+ };
19489
+ }
19490
+ function aggregateGroqChatCompletionChunks(chunks, streamResult, endEvent) {
19491
+ const aggregated = aggregateChatCompletionChunks(
19492
+ chunks,
19493
+ streamResult,
19494
+ endEvent
19495
+ );
19496
+ return {
19497
+ metrics: aggregated.metrics,
19498
+ output: aggregated.output
19499
+ };
19500
+ }
19501
+
18031
19502
  // src/instrumentation/braintrust-plugin.ts
18032
19503
  var BraintrustPlugin = class extends BasePlugin {
18033
19504
  config;
@@ -18035,6 +19506,7 @@ var BraintrustPlugin = class extends BasePlugin {
18035
19506
  anthropicPlugin = null;
18036
19507
  aiSDKPlugin = null;
18037
19508
  claudeAgentSDKPlugin = null;
19509
+ cursorSDKPlugin = null;
18038
19510
  googleGenAIPlugin = null;
18039
19511
  huggingFacePlugin = null;
18040
19512
  openRouterPlugin = null;
@@ -18042,6 +19514,7 @@ var BraintrustPlugin = class extends BasePlugin {
18042
19514
  mistralPlugin = null;
18043
19515
  googleADKPlugin = null;
18044
19516
  coherePlugin = null;
19517
+ groqPlugin = null;
18045
19518
  constructor(config = {}) {
18046
19519
  super();
18047
19520
  this.config = config;
@@ -18064,6 +19537,10 @@ var BraintrustPlugin = class extends BasePlugin {
18064
19537
  this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
18065
19538
  this.claudeAgentSDKPlugin.enable();
18066
19539
  }
19540
+ if (integrations.cursorSDK !== false && integrations.cursor !== false) {
19541
+ this.cursorSDKPlugin = new CursorSDKPlugin();
19542
+ this.cursorSDKPlugin.enable();
19543
+ }
18067
19544
  if (integrations.googleGenAI !== false && integrations.google !== false) {
18068
19545
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
18069
19546
  this.googleGenAIPlugin.enable();
@@ -18092,6 +19569,10 @@ var BraintrustPlugin = class extends BasePlugin {
18092
19569
  this.coherePlugin = new CoherePlugin();
18093
19570
  this.coherePlugin.enable();
18094
19571
  }
19572
+ if (integrations.groq !== false) {
19573
+ this.groqPlugin = new GroqPlugin();
19574
+ this.groqPlugin.enable();
19575
+ }
18095
19576
  }
18096
19577
  onDisable() {
18097
19578
  if (this.openaiPlugin) {
@@ -18110,6 +19591,10 @@ var BraintrustPlugin = class extends BasePlugin {
18110
19591
  this.claudeAgentSDKPlugin.disable();
18111
19592
  this.claudeAgentSDKPlugin = null;
18112
19593
  }
19594
+ if (this.cursorSDKPlugin) {
19595
+ this.cursorSDKPlugin.disable();
19596
+ this.cursorSDKPlugin = null;
19597
+ }
18113
19598
  if (this.googleGenAIPlugin) {
18114
19599
  this.googleGenAIPlugin.disable();
18115
19600
  this.googleGenAIPlugin = null;
@@ -18138,6 +19623,10 @@ var BraintrustPlugin = class extends BasePlugin {
18138
19623
  this.coherePlugin.disable();
18139
19624
  this.coherePlugin = null;
18140
19625
  }
19626
+ if (this.groqPlugin) {
19627
+ this.groqPlugin.disable();
19628
+ this.groqPlugin = null;
19629
+ }
18141
19630
  }
18142
19631
  };
18143
19632
 
@@ -18211,6 +19700,8 @@ var PluginRegistry = class {
18211
19700
  google: true,
18212
19701
  huggingface: true,
18213
19702
  claudeAgentSDK: true,
19703
+ cursor: true,
19704
+ cursorSDK: true,
18214
19705
  openrouter: true,
18215
19706
  openrouterAgent: true,
18216
19707
  mistral: true,
@@ -18227,7 +19718,11 @@ var PluginRegistry = class {
18227
19718
  if (disabledList) {
18228
19719
  const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
18229
19720
  for (const sdk of disabled) {
18230
- integrations[sdk] = false;
19721
+ if (sdk === "cursor-sdk") {
19722
+ integrations.cursorSDK = false;
19723
+ } else {
19724
+ integrations[sdk] = false;
19725
+ }
18231
19726
  }
18232
19727
  }
18233
19728
  return { integrations };