@raindrop-ai/ai-sdk 0.1.1 → 0.2.1

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- // ../core/dist/chunk-Y5LUB7OE.js
3
+ // ../core/dist/chunk-QNWZIOOY.js
4
4
  function normalizeFeatureFlags(input) {
5
5
  if (Array.isArray(input)) {
6
6
  return Object.fromEntries(input.map((name) => [name, "true"]));
@@ -443,19 +443,52 @@ function projectIdHeaders(projectId) {
443
443
  var SHUTDOWN_DEADLINE_MS = 1e4;
444
444
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
445
445
  function mergePatches(target, source) {
446
- var _a, _b, _c, _d, _e, _f;
446
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
447
447
  const out = { ...target, ...source };
448
448
  if (target.properties || source.properties) {
449
449
  out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
450
450
  }
451
+ if (target.usage || source.usage) {
452
+ out.usage = { ...(_c = target.usage) != null ? _c : {} };
453
+ if (((_d = source.usage) == null ? void 0 : _d.promptTokens) !== void 0) {
454
+ out.usage.promptTokens = source.usage.promptTokens;
455
+ }
456
+ if (((_e = source.usage) == null ? void 0 : _e.completionTokens) !== void 0) {
457
+ out.usage.completionTokens = source.usage.completionTokens;
458
+ }
459
+ }
460
+ if (source.error === void 0) {
461
+ out.error = target.error;
462
+ }
451
463
  if (target.featureFlags || source.featureFlags) {
452
- out.featureFlags = { ...(_c = target.featureFlags) != null ? _c : {}, ...(_d = source.featureFlags) != null ? _d : {} };
464
+ out.featureFlags = { ...(_f = target.featureFlags) != null ? _f : {}, ...(_g = source.featureFlags) != null ? _g : {} };
453
465
  }
454
466
  if (target.attachments || source.attachments) {
455
- out.attachments = [...(_e = target.attachments) != null ? _e : [], ...(_f = source.attachments) != null ? _f : []];
467
+ out.attachments = [...(_h = target.attachments) != null ? _h : [], ...(_i = source.attachments) != null ? _i : []];
456
468
  }
457
469
  return out;
458
470
  }
471
+ function isErrorLike(value) {
472
+ return value !== null && typeof value === "object";
473
+ }
474
+ function eventTelemetryProperties(patch) {
475
+ var _a, _b;
476
+ const properties = {};
477
+ if (((_a = patch.usage) == null ? void 0 : _a.promptTokens) !== void 0 && Number.isFinite(patch.usage.promptTokens)) {
478
+ properties["ai.usage.prompt_tokens"] = patch.usage.promptTokens;
479
+ }
480
+ if (((_b = patch.usage) == null ? void 0 : _b.completionTokens) !== void 0 && Number.isFinite(patch.usage.completionTokens)) {
481
+ properties["ai.usage.completion_tokens"] = patch.usage.completionTokens;
482
+ }
483
+ if (patch.error !== void 0 && patch.error !== null) {
484
+ const constructorName = patch.error instanceof Error && patch.error.constructor !== Error ? patch.error.constructor.name : void 0;
485
+ const errorType = patch.error instanceof Error ? patch.error.name && patch.error.name !== "Error" ? patch.error.name : constructorName || patch.error.name || "Error" : isErrorLike(patch.error) && typeof patch.error.name === "string" && patch.error.name.length > 0 ? patch.error.name : "Error";
486
+ const errorMessage = patch.error instanceof Error ? patch.error.message : isErrorLike(patch.error) && typeof patch.error.message === "string" ? patch.error.message : String(patch.error);
487
+ properties["error.type"] = errorType;
488
+ properties["error.message"] = errorMessage;
489
+ }
490
+ return properties;
491
+ }
459
492
  var EventShipper = class {
460
493
  constructor(opts) {
461
494
  this.buffers = /* @__PURE__ */ new Map();
@@ -704,6 +737,11 @@ var EventShipper = class {
704
737
  return;
705
738
  }
706
739
  const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
740
+ let telemetryProperties = {};
741
+ try {
742
+ telemetryProperties = eventTelemetryProperties(accumulated);
743
+ } catch (e) {
744
+ }
707
745
  const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
708
746
  const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
709
747
  const payload = {
@@ -713,12 +751,13 @@ var EventShipper = class {
713
751
  timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
714
752
  ai_data: {
715
753
  input: accumulated.input,
716
- output: accumulated.output,
754
+ output: accumulated.error !== void 0 && accumulated.error !== null ? void 0 : accumulated.output,
717
755
  model: accumulated.model,
718
756
  convo_id: convoId
719
757
  },
720
758
  properties: {
721
759
  ...restProperties,
760
+ ...telemetryProperties,
722
761
  ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
723
762
  $context: this.context
724
763
  },
@@ -787,6 +826,193 @@ var EventShipper = class {
787
826
  }
788
827
  }
789
828
  };
829
+ var MODEL_USAGE_ATTRIBUTES = {
830
+ providerName: "gen_ai.provider.name",
831
+ requestModel: "gen_ai.request.model",
832
+ responseModel: "gen_ai.response.model",
833
+ inputTokens: "gen_ai.usage.input_tokens",
834
+ outputTokens: "gen_ai.usage.output_tokens",
835
+ reasoningTokens: "gen_ai.usage.reasoning_tokens",
836
+ cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
837
+ cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
838
+ nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
839
+ nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
840
+ reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
841
+ cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
842
+ cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
843
+ };
844
+ var MODEL_PROVIDER_NAMES = [
845
+ ["google.vertex", "google-vertex"],
846
+ ["vertex.anthropic", "google-vertex"],
847
+ ["amazon-bedrock", "amazon-bedrock"],
848
+ ["bedrock", "amazon-bedrock"],
849
+ ["anthropic", "anthropic"],
850
+ ["openai", "openai"],
851
+ ["google", "google"],
852
+ ["azure", "azure"],
853
+ ["openrouter", "openrouter"]
854
+ ];
855
+ function canonicalModelProvider(provider) {
856
+ var _a;
857
+ const normalizedProvider = provider.trim().toLowerCase();
858
+ if (normalizedProvider === "gateway") return "vercel";
859
+ const match = MODEL_PROVIDER_NAMES.find(
860
+ ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
861
+ );
862
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
863
+ }
864
+ function tokenCount(value) {
865
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
866
+ }
867
+ function exclusiveTokens({
868
+ explicit,
869
+ total,
870
+ parts,
871
+ semantics
872
+ }) {
873
+ if (explicit !== void 0) return explicit;
874
+ if (total === void 0) return void 0;
875
+ if (semantics === "exclusive") return total;
876
+ const observedParts = parts.filter((part) => part !== void 0 && part > 0);
877
+ if (semantics === void 0 && observedParts.length > 0) return void 0;
878
+ const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
879
+ return exclusive >= 0 ? exclusive : void 0;
880
+ }
881
+ function buildModelUsageAttributes(usage) {
882
+ const inputTokens = tokenCount(usage.inputTokens);
883
+ const outputTokens = tokenCount(usage.outputTokens);
884
+ const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
885
+ const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
886
+ const reasoningTokens = tokenCount(usage.reasoningTokens);
887
+ const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
888
+ const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
889
+ const nonCachedInputTokens = exclusiveTokens({
890
+ explicit: explicitNonCachedInputTokens,
891
+ total: inputTokens,
892
+ parts: [cacheReadInputTokens, cacheWriteInputTokens],
893
+ semantics: usage.inputTokenSemantics
894
+ });
895
+ const nonReasoningOutputTokens = exclusiveTokens({
896
+ explicit: explicitNonReasoningOutputTokens,
897
+ total: outputTokens,
898
+ parts: [reasoningTokens],
899
+ semantics: usage.outputTokenSemantics
900
+ });
901
+ const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
902
+ // backend consumes this complete raindrop.* set as one atomic billing-pool contract.
903
+ attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
904
+ attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
905
+ attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
906
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
907
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
908
+ ] : [];
909
+ return [
910
+ attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
911
+ attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
912
+ attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
913
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
914
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
915
+ ...exclusivePoolAttributes
916
+ ].filter((attribute) => attribute !== void 0);
917
+ }
918
+ var STRING_ALIASES = {
919
+ [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
920
+ };
921
+ var NUMBER_ALIASES = {
922
+ [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
923
+ "gen_ai.usage.prompt_tokens",
924
+ "ai.usage.prompt_tokens",
925
+ "ai.usage.promptTokens",
926
+ "ai.usage.input_tokens",
927
+ "ai.usage.inputTokens"
928
+ ],
929
+ [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
930
+ "gen_ai.usage.completion_tokens",
931
+ "ai.usage.completion_tokens",
932
+ "ai.usage.completionTokens",
933
+ "ai.usage.output_tokens",
934
+ "ai.usage.outputTokens"
935
+ ],
936
+ [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
937
+ "gen_ai.usage.reasoning.output_tokens",
938
+ "ai.usage.reasoningTokens",
939
+ "ai.usage.thoughts_tokens"
940
+ ],
941
+ [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
942
+ "gen_ai.usage.cache_read_tokens",
943
+ "gen_ai.usage.cache_read.input_tokens",
944
+ "ai.usage.cachedInputTokens",
945
+ "ai.usage.cached_tokens",
946
+ "ai.usage.cache_read_tokens",
947
+ "ai.usage.cache_read_input_tokens",
948
+ "ai.usage.cacheReadInputTokens"
949
+ ],
950
+ [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
951
+ "gen_ai.usage.cache_creation_input_tokens",
952
+ "gen_ai.usage.cache_creation.input_tokens",
953
+ "ai.usage.cacheWriteInputTokens",
954
+ "ai.usage.cache_creation_input_tokens",
955
+ "ai.usage.cacheCreationInputTokens"
956
+ ]
957
+ };
958
+ function hasAttribute(attributes, key) {
959
+ return attributes.some((attribute) => attribute.key === key);
960
+ }
961
+ function findStringAttribute(attributes, keys) {
962
+ return attributes.find(
963
+ (attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
964
+ );
965
+ }
966
+ function findNumberAttribute(attributes, keys) {
967
+ return attributes.find((attribute) => {
968
+ if (!keys.includes(attribute.key)) return false;
969
+ if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
970
+ return true;
971
+ }
972
+ const intValue = attribute.value.intValue;
973
+ return integerValue(intValue) !== void 0;
974
+ });
975
+ }
976
+ function integerValue(value) {
977
+ if (typeof value === "number") {
978
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
979
+ }
980
+ if (typeof value !== "string") return void 0;
981
+ const parsed = Number(value);
982
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
983
+ }
984
+ function appendAlias(attributes, target, source) {
985
+ if (!source || hasAttribute(attributes, target)) return attributes;
986
+ return [...attributes, { key: target, value: { ...source.value } }];
987
+ }
988
+ function appendProviderAlias(attributes) {
989
+ if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
990
+ const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
991
+ if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
992
+ const attribute = attrString(
993
+ MODEL_USAGE_ATTRIBUTES.providerName,
994
+ canonicalModelProvider(source.value.stringValue)
995
+ );
996
+ return attribute ? [...attributes, attribute] : attributes;
997
+ }
998
+ function normalizeModelUsageSpan(span) {
999
+ const original = span.attributes;
1000
+ if (!original || original.length === 0) return span;
1001
+ const responseModel = findStringAttribute(original, [
1002
+ MODEL_USAGE_ATTRIBUTES.responseModel,
1003
+ "ai.response.model"
1004
+ ]);
1005
+ if (!responseModel) return span;
1006
+ let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
1007
+ attributes = appendProviderAlias(attributes);
1008
+ for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
1009
+ attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
1010
+ }
1011
+ for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
1012
+ attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
1013
+ }
1014
+ return attributes === original ? span : { ...span, attributes };
1015
+ }
790
1016
  var DEFAULT_SECRET_KEY_NAMES = [
791
1017
  "apikey",
792
1018
  "apisecret",
@@ -876,6 +1102,13 @@ function redactJsonAttributeValue(key, value) {
876
1102
  if (scrubbedJson === json) return void 0;
877
1103
  return { stringValue: scrubbedJson };
878
1104
  }
1105
+ function identityAttrs(args) {
1106
+ return [
1107
+ attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
1108
+ attrString("ai.telemetry.metadata.raindrop.convoId", args.convoId),
1109
+ attrString("ai.telemetry.metadata.raindrop.eventName", args.eventName)
1110
+ ];
1111
+ }
879
1112
  function applyOtelSpanAttributeLimit(limit) {
880
1113
  var _a, _b;
881
1114
  try {
@@ -980,6 +1213,10 @@ var TraceShipper = class {
980
1213
  return null;
981
1214
  }
982
1215
  }
1216
+ try {
1217
+ current = normalizeModelUsageSpan(current);
1218
+ } catch (e) {
1219
+ }
983
1220
  if (!this.disableDefaultRedaction) {
984
1221
  current = defaultTransformSpan(current);
985
1222
  }
@@ -1000,6 +1237,7 @@ var TraceShipper = class {
1000
1237
  const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
1001
1238
  const attrs = [
1002
1239
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1240
+ ...identityAttrs(args),
1003
1241
  attrString("ai.operationId", args.operationId)
1004
1242
  ];
1005
1243
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
@@ -1055,7 +1293,8 @@ var TraceShipper = class {
1055
1293
  var _a;
1056
1294
  const ids = createSpanIds(args.parent);
1057
1295
  const attrs = [
1058
- attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId)
1296
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1297
+ ...identityAttrs(args)
1059
1298
  ];
1060
1299
  if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1061
1300
  const otlp = buildOtlpSpan({
@@ -1311,7 +1550,7 @@ async function* asyncGeneratorWithCurrent(span, gen) {
1311
1550
  // package.json
1312
1551
  var package_default = {
1313
1552
  name: "@raindrop-ai/ai-sdk",
1314
- version: "0.1.1"};
1553
+ version: "0.2.1"};
1315
1554
 
1316
1555
  // src/internal/version.ts
1317
1556
  var libraryName = package_default.name;
@@ -2008,6 +2247,15 @@ function attrsFromHeaders(headers) {
2008
2247
  if (!isRecord(headers)) return [];
2009
2248
  return Object.entries(headers).filter(([, v]) => typeof v === "string").map(([k, v]) => attrString(`ai.request.headers.${k}`, v));
2010
2249
  }
2250
+ function attrsFromModelProvider(provider) {
2251
+ if (typeof provider !== "string" || provider.length === 0) return [];
2252
+ const providerName = canonicalModelProvider(provider);
2253
+ return [
2254
+ attrString("ai.model.provider", provider),
2255
+ attrString(MODEL_USAGE_ATTRIBUTES.providerName, providerName),
2256
+ attrString("gen_ai.system", provider)
2257
+ ];
2258
+ }
2011
2259
  function attrsFromSettings(args) {
2012
2260
  if (!isRecord(args)) return [];
2013
2261
  const result = [];
@@ -2190,6 +2438,126 @@ function runWithParentToolContext(ctx, fn) {
2190
2438
  return getStorage2().run(ctx, fn);
2191
2439
  }
2192
2440
 
2441
+ // src/internal/usage.ts
2442
+ function firstTokenCount(...values) {
2443
+ for (const value of values) {
2444
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
2445
+ return value;
2446
+ }
2447
+ }
2448
+ return void 0;
2449
+ }
2450
+ function flatUsageSemantics(provider) {
2451
+ const normalizedProvider = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
2452
+ if (normalizedProvider === "anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("anthropic.")) || normalizedProvider === "vertex.anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("vertex.anthropic."))) {
2453
+ return {
2454
+ inputTokenSemantics: "exclusive",
2455
+ outputTokenSemantics: "total"
2456
+ };
2457
+ }
2458
+ if (normalizedProvider === "openai" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("openai.")) || normalizedProvider === "azure" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("azure."))) {
2459
+ return {
2460
+ inputTokenSemantics: "total",
2461
+ outputTokenSemantics: "total"
2462
+ };
2463
+ }
2464
+ if (normalizedProvider === "google" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("google."))) {
2465
+ return {
2466
+ inputTokenSemantics: "total",
2467
+ // Google v5 reports candidate output and thoughts separately.
2468
+ outputTokenSemantics: "exclusive"
2469
+ };
2470
+ }
2471
+ return {};
2472
+ }
2473
+ var CACHE_WRITE_METADATA_KEYS = [
2474
+ ["anthropic", "cacheCreationInputTokens"],
2475
+ ["openai", "cacheWriteTokens"],
2476
+ ["bedrock", "cacheWriteInputTokens"]
2477
+ ];
2478
+ function cacheWriteTokensFromProviderMetadata(providerMetadata) {
2479
+ if (!isRecord(providerMetadata)) return void 0;
2480
+ return firstTokenCount(
2481
+ ...CACHE_WRITE_METADATA_KEYS.flatMap(([namespace, key]) => {
2482
+ const scope = providerMetadata[namespace];
2483
+ if (!isRecord(scope)) return [];
2484
+ const usage = scope["usage"];
2485
+ return [scope[key], isRecord(usage) ? usage[key] : void 0];
2486
+ })
2487
+ );
2488
+ }
2489
+ function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
2490
+ if (!isRecord(usage)) return {};
2491
+ const inputTokenValue = usage["inputTokens"];
2492
+ const outputTokenValue = usage["outputTokens"];
2493
+ const inputTokenDetails = usage["inputTokenDetails"];
2494
+ const outputTokenDetails = usage["outputTokenDetails"];
2495
+ const hasStructuredUsage = isRecord(inputTokenValue) || isRecord(outputTokenValue) || isRecord(inputTokenDetails) || isRecord(outputTokenDetails);
2496
+ const inputTokens = firstTokenCount(
2497
+ isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
2498
+ inputTokenValue,
2499
+ usage["promptTokens"],
2500
+ usage["prompt_tokens"]
2501
+ );
2502
+ const outputTokens = firstTokenCount(
2503
+ isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
2504
+ outputTokenValue,
2505
+ usage["completionTokens"],
2506
+ usage["completion_tokens"]
2507
+ );
2508
+ const reasoningTokens = firstTokenCount(
2509
+ isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
2510
+ isRecord(outputTokenDetails) ? outputTokenDetails["reasoningTokens"] : void 0,
2511
+ usage["reasoningTokens"],
2512
+ usage["completionReasoningTokens"],
2513
+ usage["completion_reasoning_tokens"],
2514
+ usage["reasoning_tokens"],
2515
+ usage["thinkingTokens"],
2516
+ usage["thinking_tokens"]
2517
+ );
2518
+ const cacheReadInputTokens = firstTokenCount(
2519
+ isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
2520
+ isRecord(inputTokenDetails) ? inputTokenDetails["cacheReadTokens"] : void 0,
2521
+ usage["cachedInputTokens"],
2522
+ usage["promptCachedTokens"],
2523
+ usage["prompt_cached_tokens"]
2524
+ );
2525
+ const cacheWriteInputTokens = firstTokenCount(
2526
+ isRecord(inputTokenValue) ? inputTokenValue["cacheWrite"] : void 0,
2527
+ isRecord(inputTokenDetails) ? inputTokenDetails["cacheWriteTokens"] : void 0,
2528
+ usage["cacheWriteInputTokens"],
2529
+ usage["cacheCreationInputTokens"],
2530
+ usage["cache_creation_input_tokens"],
2531
+ cacheWriteTokensFromProviderMetadata(providerMetadata)
2532
+ );
2533
+ const nonCachedInputTokens = firstTokenCount(
2534
+ isRecord(inputTokenValue) ? inputTokenValue["noCache"] : void 0,
2535
+ isRecord(inputTokenDetails) ? inputTokenDetails["noCacheTokens"] : void 0
2536
+ );
2537
+ const nonReasoningOutputTokens = firstTokenCount(
2538
+ isRecord(outputTokenValue) ? outputTokenValue["text"] : void 0,
2539
+ isRecord(outputTokenDetails) ? outputTokenDetails["textTokens"] : void 0
2540
+ );
2541
+ const totalTokens = firstTokenCount(
2542
+ usage["totalTokens"],
2543
+ usage["tokens"],
2544
+ usage["total_tokens"],
2545
+ inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
2546
+ );
2547
+ return {
2548
+ inputTokens,
2549
+ outputTokens,
2550
+ totalTokens,
2551
+ nonCachedInputTokens,
2552
+ nonReasoningOutputTokens,
2553
+ reasoningTokens,
2554
+ cacheReadInputTokens,
2555
+ cachedInputTokens: cacheReadInputTokens,
2556
+ cacheWriteInputTokens,
2557
+ ...hasStructuredUsage ? {} : flatUsageSemantics(provider)
2558
+ };
2559
+ }
2560
+
2193
2561
  // src/internal/raindrop-telemetry-integration.ts
2194
2562
  function hasUnresolvedToolApproval(event) {
2195
2563
  var _a;
@@ -2246,7 +2614,7 @@ var RaindropTelemetryIntegration = class {
2246
2614
  };
2247
2615
  // ── onStart ─────────────────────────────────────────────────────────────
2248
2616
  this.onStart = (event) => {
2249
- var _a, _b, _c, _d, _e;
2617
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2250
2618
  if (event.isEnabled === false) return;
2251
2619
  const isEmbed = event.operationId === "ai.embed" || event.operationId === "ai.embedMany";
2252
2620
  const recordInputs = event.recordInputs !== false;
@@ -2256,15 +2624,20 @@ var RaindropTelemetryIntegration = class {
2256
2624
  const callContextMetadata = getCurrentRaindropCallMetadata();
2257
2625
  const metadata = eventMetadata2 != null ? eventMetadata2 : callContextMetadata == null ? void 0 : callContextMetadata.rawMetadata;
2258
2626
  const callMeta = this.extractRaindropMetadata(metadata);
2627
+ const identity = {
2628
+ userId: (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId,
2629
+ convoId: (_d = callMeta.convoId) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.convoId,
2630
+ eventName: (_f = callMeta.eventName) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.eventName
2631
+ };
2259
2632
  const inherited = getContextManager().getParentSpanIds();
2260
2633
  const eventIdGenerated = (metadata == null ? void 0 : metadata["raindrop.internal.eventIdGenerated"]) === "true" || (metadata == null ? void 0 : metadata["raindrop.internal.eventIdGenerated"]) === true || (callContextMetadata == null ? void 0 : callContextMetadata.eventIdGenerated) === true;
2261
2634
  const explicitEventId = callMeta.eventId && !eventIdGenerated ? callMeta.eventId : void 0;
2262
- const eventId = (_d = (_c = (_b = explicitEventId != null ? explicitEventId : (_a = this.defaultContext) == null ? void 0 : _a.eventId) != null ? _b : inherited == null ? void 0 : inherited.eventId) != null ? _c : callMeta.eventId) != null ? _d : randomUUID();
2635
+ const eventId = (_j = (_i = (_h = explicitEventId != null ? explicitEventId : (_g = this.defaultContext) == null ? void 0 : _g.eventId) != null ? _h : inherited == null ? void 0 : inherited.eventId) != null ? _i : callMeta.eventId) != null ? _j : randomUUID();
2263
2636
  const inheritedParent = inherited && inherited.eventId === eventId ? { traceIdB64: inherited.traceIdB64, spanIdB64: inherited.spanIdB64 } : void 0;
2264
2637
  const { operationName, resourceName } = opName(event.operationId, functionId);
2265
2638
  const parentToolContext = !isEmbed && this.subagentWrapping ? getCurrentParentToolContext() : void 0;
2266
2639
  const metadataSubagentName = !isEmbed && this.subagentWrapping && parentToolContext === void 0 ? typeof (metadata == null ? void 0 : metadata["eve.subagent.name"]) === "string" ? metadata["eve.subagent.name"] : typeof (metadata == null ? void 0 : metadata["ash.subagent.name"]) === "string" ? metadata["ash.subagent.name"] : void 0 : void 0;
2267
- const subagentName = (_e = parentToolContext == null ? void 0 : parentToolContext.toolName) != null ? _e : metadataSubagentName;
2640
+ const subagentName = (_k = parentToolContext == null ? void 0 : parentToolContext.toolName) != null ? _k : metadataSubagentName;
2268
2641
  let subagentToolCallSpan;
2269
2642
  let rootParentOverride;
2270
2643
  if (subagentName && this.sendTraces) {
@@ -2277,6 +2650,7 @@ var RaindropTelemetryIntegration = class {
2277
2650
  name: subagentName,
2278
2651
  parent: inheritedParent,
2279
2652
  eventId,
2653
+ ...identity,
2280
2654
  operationId: "ai.toolCall",
2281
2655
  attributes: [
2282
2656
  attrString("operation.name", "ai.toolCall"),
@@ -2293,6 +2667,7 @@ var RaindropTelemetryIntegration = class {
2293
2667
  name: "agent.subagent",
2294
2668
  parent: subagentParentRef,
2295
2669
  eventId,
2670
+ ...identity,
2296
2671
  operationId: "agent.subagent",
2297
2672
  attributes: [
2298
2673
  attrString("operation.name", "agent.subagent"),
@@ -2320,6 +2695,7 @@ var RaindropTelemetryIntegration = class {
2320
2695
  name: event.operationId,
2321
2696
  parent: rootParentOverride != null ? rootParentOverride : inheritedParent,
2322
2697
  eventId,
2698
+ ...identity,
2323
2699
  operationId: event.operationId,
2324
2700
  attributes: [
2325
2701
  attrString("operation.name", operationName),
@@ -2327,13 +2703,14 @@ var RaindropTelemetryIntegration = class {
2327
2703
  attrString("ai.telemetry.functionId", functionId),
2328
2704
  attrString("ai.model.provider", event.provider),
2329
2705
  attrString("ai.model.id", event.modelId),
2330
- // Filter out raindrop.eventId from metadata attrs since TraceShipper
2331
- // already sets it via the eventId arg. Without this, eventMetadata()'s
2332
- // auto-generated ID would duplicate and override the resolved one.
2706
+ // Filter out identity keys (eventId/userId/convoId/eventName) from
2707
+ // metadata attrs since TraceShipper already stamps them via dedicated
2708
+ // args. Without this, eventMetadata()'s auto-generated ID would
2709
+ // duplicate and override the resolved one.
2333
2710
  ...attrsFromTelemetryMetadata(
2334
2711
  metadata ? Object.fromEntries(
2335
2712
  Object.entries(metadata).filter(
2336
- ([k]) => k !== "raindrop.eventId" && k !== "raindrop.internal.eventIdGenerated"
2713
+ ([k]) => k !== "raindrop.eventId" && k !== "raindrop.internal.eventIdGenerated" && k !== "raindrop.userId" && k !== "raindrop.convoId" && k !== "raindrop.eventName"
2337
2714
  )
2338
2715
  ) : void 0
2339
2716
  ),
@@ -2345,10 +2722,13 @@ var RaindropTelemetryIntegration = class {
2345
2722
  this.callStates.set(event.callId, {
2346
2723
  operationId: event.operationId,
2347
2724
  eventId,
2725
+ identity,
2348
2726
  rootSpan,
2349
2727
  rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
2350
2728
  stepSpan: void 0,
2351
2729
  stepParent: void 0,
2730
+ stepProvider: void 0,
2731
+ stepModelId: void 0,
2352
2732
  toolSpans: /* @__PURE__ */ new Map(),
2353
2733
  embedSpans: /* @__PURE__ */ new Map(),
2354
2734
  parentContextToolCallIds: /* @__PURE__ */ new Set(),
@@ -2396,20 +2776,22 @@ var RaindropTelemetryIntegration = class {
2396
2776
  name: stepOperationId,
2397
2777
  parent: state.rootParent,
2398
2778
  eventId: state.eventId,
2779
+ ...state.identity,
2399
2780
  operationId: stepOperationId,
2400
2781
  attributes: [
2401
2782
  attrString("operation.name", operationName),
2402
2783
  attrString("resource.name", resourceName),
2403
2784
  attrString("ai.telemetry.functionId", state.functionId),
2404
- attrString("ai.model.provider", event.provider),
2785
+ ...attrsFromModelProvider(event.provider),
2405
2786
  attrString("ai.model.id", event.modelId),
2406
- attrString("gen_ai.system", event.provider),
2407
- attrString("gen_ai.request.model", event.modelId),
2787
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
2408
2788
  ...inputAttrs
2409
2789
  ]
2410
2790
  });
2411
2791
  state.stepSpan = stepSpan;
2412
2792
  state.stepParent = this.spanParentRef(stepSpan);
2793
+ state.stepProvider = event.provider;
2794
+ state.stepModelId = event.modelId;
2413
2795
  };
2414
2796
  this.onToolExecutionStart = (event) => this.toolExecutionStart(event);
2415
2797
  this.onToolExecutionEnd = (event) => this.toolExecutionEnd(event);
@@ -2460,23 +2842,24 @@ var RaindropTelemetryIntegration = class {
2460
2842
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2461
2843
  const state = this.getState(event.callId);
2462
2844
  if (!(state == null ? void 0 : state.stepSpan)) return;
2845
+ const responseModelId = (_b = (_a = event.response) == null ? void 0 : _a.modelId) != null ? _b : state.stepModelId;
2463
2846
  const outputAttrs = [];
2464
2847
  if (state.recordOutputs) {
2465
2848
  outputAttrs.push(
2466
2849
  attrString("ai.response.finishReason", event.finishReason),
2467
- attrString("ai.response.text", capText2((_a = event.text) != null ? _a : void 0)),
2468
- attrString("ai.response.id", (_b = event.response) == null ? void 0 : _b.id),
2469
- attrString("ai.response.model", (_c = event.response) == null ? void 0 : _c.modelId),
2850
+ attrString("ai.response.text", capText2((_c = event.text) != null ? _c : void 0)),
2851
+ attrString("ai.response.id", (_d = event.response) == null ? void 0 : _d.id),
2852
+ attrString("ai.response.model", responseModelId),
2470
2853
  attrString(
2471
2854
  "ai.response.timestamp",
2472
- ((_d = event.response) == null ? void 0 : _d.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_e = event.response) == null ? void 0 : _e.timestamp
2855
+ ((_e = event.response) == null ? void 0 : _e.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_f = event.response) == null ? void 0 : _f.timestamp
2473
2856
  ),
2474
2857
  attrString(
2475
2858
  "ai.response.providerMetadata",
2476
2859
  event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
2477
2860
  )
2478
2861
  );
2479
- if (((_f = event.toolCalls) == null ? void 0 : _f.length) > 0) {
2862
+ if (((_g = event.toolCalls) == null ? void 0 : _g.length) > 0) {
2480
2863
  outputAttrs.push(
2481
2864
  attrString(
2482
2865
  "ai.response.toolCalls",
@@ -2490,7 +2873,7 @@ var RaindropTelemetryIntegration = class {
2490
2873
  )
2491
2874
  );
2492
2875
  }
2493
- if (((_g = event.reasoning) == null ? void 0 : _g.length) > 0) {
2876
+ if (((_h = event.reasoning) == null ? void 0 : _h.length) > 0) {
2494
2877
  const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
2495
2878
  if (reasoningText) {
2496
2879
  outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
@@ -2499,25 +2882,31 @@ var RaindropTelemetryIntegration = class {
2499
2882
  }
2500
2883
  outputAttrs.push(
2501
2884
  attrStringArray("gen_ai.response.finish_reasons", [event.finishReason]),
2502
- attrString("gen_ai.response.id", (_h = event.response) == null ? void 0 : _h.id),
2503
- attrString("gen_ai.response.model", (_i = event.response) == null ? void 0 : _i.modelId)
2885
+ attrString("gen_ai.response.id", (_i = event.response) == null ? void 0 : _i.id),
2886
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId)
2504
2887
  );
2505
2888
  const usage = event.usage;
2506
2889
  if (usage) {
2890
+ const usageMetrics = extractUsageMetricsFromUsage(
2891
+ usage,
2892
+ state.stepProvider,
2893
+ event.providerMetadata
2894
+ );
2507
2895
  outputAttrs.push(
2508
- attrInt("ai.usage.inputTokens", usage.inputTokens),
2509
- attrInt("ai.usage.outputTokens", usage.outputTokens),
2510
- attrInt("ai.usage.totalTokens", usage.totalTokens),
2511
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
2512
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens),
2513
- attrInt("gen_ai.usage.input_tokens", usage.inputTokens),
2514
- attrInt("gen_ai.usage.output_tokens", usage.outputTokens)
2896
+ attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
2897
+ attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
2898
+ attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
2899
+ attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
2900
+ attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens),
2901
+ ...buildModelUsageAttributes(usageMetrics)
2515
2902
  );
2516
2903
  }
2517
2904
  this.emitProviderExecutedToolSpans(event, state);
2518
2905
  this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
2519
2906
  state.stepSpan = void 0;
2520
2907
  state.stepParent = void 0;
2908
+ state.stepProvider = void 0;
2909
+ state.stepModelId = void 0;
2521
2910
  };
2522
2911
  // ── onEmbedStart ────────────────────────────────────────────────────────
2523
2912
  this.onEmbedStart = (event) => {
@@ -2529,6 +2918,7 @@ var RaindropTelemetryIntegration = class {
2529
2918
  name: event.operationId,
2530
2919
  parent: state.rootParent,
2531
2920
  eventId: state.eventId,
2921
+ ...state.identity,
2532
2922
  operationId: event.operationId,
2533
2923
  attributes: [
2534
2924
  attrString("operation.name", operationName),
@@ -2591,6 +2981,8 @@ var RaindropTelemetryIntegration = class {
2591
2981
  const actualError = (_a = event.error) != null ? _a : error;
2592
2982
  if (state.stepSpan) {
2593
2983
  this.traceShipper.endSpan(state.stepSpan, { error: actualError });
2984
+ state.stepProvider = void 0;
2985
+ state.stepModelId = void 0;
2594
2986
  }
2595
2987
  for (const embedSpan of state.embedSpans.values()) {
2596
2988
  this.traceShipper.endSpan(embedSpan, { error: actualError });
@@ -2634,6 +3026,8 @@ var RaindropTelemetryIntegration = class {
2634
3026
  this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
2635
3027
  state.stepSpan = void 0;
2636
3028
  state.stepParent = void 0;
3029
+ state.stepProvider = void 0;
3030
+ state.stepModelId = void 0;
2637
3031
  }
2638
3032
  for (const embedSpan of state.embedSpans.values()) {
2639
3033
  this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
@@ -2795,6 +3189,7 @@ var RaindropTelemetryIntegration = class {
2795
3189
  name: "ai.toolCall",
2796
3190
  parent: state.stepParent,
2797
3191
  eventId: state.eventId,
3192
+ ...state.identity,
2798
3193
  operationId: "ai.toolCall",
2799
3194
  attributes: [
2800
3195
  attrString("operation.name", operationName),
@@ -2872,6 +3267,7 @@ var RaindropTelemetryIntegration = class {
2872
3267
  name: "ai.toolCall",
2873
3268
  parent: state.stepParent,
2874
3269
  eventId: state.eventId,
3270
+ ...state.identity,
2875
3271
  operationId: "ai.toolCall",
2876
3272
  attributes: [
2877
3273
  attrString("operation.name", operationName),
@@ -2931,12 +3327,13 @@ var RaindropTelemetryIntegration = class {
2931
3327
  }
2932
3328
  const usage = (_d = event.totalUsage) != null ? _d : event.usage;
2933
3329
  if (usage) {
3330
+ const usageMetrics = extractUsageMetricsFromUsage(usage);
2934
3331
  outputAttrs.push(
2935
- attrInt("ai.usage.inputTokens", usage.inputTokens),
2936
- attrInt("ai.usage.outputTokens", usage.outputTokens),
2937
- attrInt("ai.usage.totalTokens", usage.totalTokens),
2938
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
2939
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens)
3332
+ attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
3333
+ attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
3334
+ attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
3335
+ attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
3336
+ attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens)
2940
3337
  );
2941
3338
  }
2942
3339
  outputAttrs.push(attrInt("ai.toolCall.count", state.toolCallCount));
@@ -3389,14 +3786,6 @@ function runWithParentSpanContextSync(ctx, fn) {
3389
3786
  function isAsyncIterable(value) {
3390
3787
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
3391
3788
  }
3392
- function firstFiniteNumber(...values) {
3393
- for (const value of values) {
3394
- if (typeof value === "number" && Number.isFinite(value)) {
3395
- return value;
3396
- }
3397
- }
3398
- return void 0;
3399
- }
3400
3789
  function resolveUsageRecord(result) {
3401
3790
  if (!isRecord(result)) return void 0;
3402
3791
  let usage;
@@ -3412,50 +3801,7 @@ function resolveUsageRecord(result) {
3412
3801
  return isRecord(usage) ? usage : void 0;
3413
3802
  }
3414
3803
  function extractUsageMetrics(result) {
3415
- const usage = resolveUsageRecord(result);
3416
- if (!usage) return {};
3417
- const inputTokenValue = usage["inputTokens"];
3418
- const outputTokenValue = usage["outputTokens"];
3419
- const inputTokens = firstFiniteNumber(
3420
- isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
3421
- inputTokenValue,
3422
- usage["promptTokens"],
3423
- usage["prompt_tokens"]
3424
- );
3425
- const outputTokens = firstFiniteNumber(
3426
- isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
3427
- outputTokenValue,
3428
- usage["completionTokens"],
3429
- usage["completion_tokens"]
3430
- );
3431
- const totalTokens = firstFiniteNumber(
3432
- usage["totalTokens"],
3433
- usage["tokens"],
3434
- usage["total_tokens"],
3435
- inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
3436
- );
3437
- const reasoningTokens = firstFiniteNumber(
3438
- isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
3439
- usage["reasoningTokens"],
3440
- usage["completionReasoningTokens"],
3441
- usage["completion_reasoning_tokens"],
3442
- usage["reasoning_tokens"],
3443
- usage["thinkingTokens"],
3444
- usage["thinking_tokens"]
3445
- );
3446
- const cachedInputTokens = firstFiniteNumber(
3447
- isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
3448
- usage["cachedInputTokens"],
3449
- usage["promptCachedTokens"],
3450
- usage["prompt_cached_tokens"]
3451
- );
3452
- return {
3453
- inputTokens,
3454
- outputTokens,
3455
- totalTokens,
3456
- reasoningTokens,
3457
- cachedInputTokens
3458
- };
3804
+ return extractUsageMetricsFromUsage(resolveUsageRecord(result));
3459
3805
  }
3460
3806
  function isObjectOperation(operation) {
3461
3807
  return operation === "generateObject" || operation === "streamObject";
@@ -3539,6 +3885,9 @@ function teeStreamObjectBaseStream(result) {
3539
3885
  } catch (e) {
3540
3886
  }
3541
3887
  }
3888
+ function identityFromContext(ctx) {
3889
+ return { userId: ctx.userId, convoId: ctx.convoId, eventName: ctx.eventName };
3890
+ }
3542
3891
  function setupOperation(params) {
3543
3892
  var _a, _b, _c;
3544
3893
  const {
@@ -3570,6 +3919,7 @@ function setupOperation(params) {
3570
3919
  name: outerOperationId,
3571
3920
  parent: inheritedParent,
3572
3921
  eventId,
3922
+ ...identityFromContext(mergedCtx),
3573
3923
  operationId: outerOperationId,
3574
3924
  attributes: [
3575
3925
  attrString("operation.name", operationName),
@@ -3578,9 +3928,6 @@ function setupOperation(params) {
3578
3928
  attrString("ai.model.provider", modelInfoFromArgs.provider),
3579
3929
  attrString("ai.model.id", modelInfoFromArgs.modelId),
3580
3930
  attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
3581
- attrString("ai.telemetry.metadata.raindrop.eventName", mergedCtx.eventName),
3582
- attrString("ai.telemetry.metadata.raindrop.ai.userId", mergedCtx.userId),
3583
- attrString("ai.telemetry.metadata.raindrop.convoId", mergedCtx.convoId),
3584
3931
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
3585
3932
  ...attrsFromHeaders(isRecord(arg) ? arg["headers"] : void 0),
3586
3933
  ...attrsFromSettings(arg),
@@ -3670,6 +4017,7 @@ function createFinalize(params) {
3670
4017
  responseMessages,
3671
4018
  rootSpan: setup.rootSpan,
3672
4019
  eventId: setup.eventId,
4020
+ ...identityFromContext(setup.ctx),
3673
4021
  telemetry: setup.telemetry,
3674
4022
  toolCalls: setup.toolCalls,
3675
4023
  traceShipper,
@@ -3708,6 +4056,11 @@ function createFinalize(params) {
3708
4056
  input,
3709
4057
  output,
3710
4058
  model: finalModel,
4059
+ usage: {
4060
+ promptTokens: usage == null ? void 0 : usage.inputTokens,
4061
+ completionTokens: usage == null ? void 0 : usage.outputTokens
4062
+ },
4063
+ error,
3711
4064
  properties: patch.properties,
3712
4065
  featureFlags: patch.featureFlags,
3713
4066
  attachments: patch.attachments,
@@ -3742,6 +4095,7 @@ function startToolSpan(toolCall, rootSpan, ctx, startTimeUnixNano) {
3742
4095
  name: "ai.toolCall",
3743
4096
  parent: { traceIdB64: rootSpan.ids.traceIdB64, spanIdB64: rootSpan.ids.spanIdB64 },
3744
4097
  eventId: ctx.eventId,
4098
+ ...identityFromContext(ctx),
3745
4099
  operationId: "ai.toolCall",
3746
4100
  attributes: [
3747
4101
  attrString("operation.name", operationName),
@@ -3779,6 +4133,9 @@ function emitTranscriptToolCallSpans(params) {
3779
4133
  }
3780
4134
  const ctx = {
3781
4135
  eventId: params.eventId,
4136
+ userId: params.userId,
4137
+ convoId: params.convoId,
4138
+ eventName: params.eventName,
3782
4139
  telemetry: params.telemetry,
3783
4140
  traceShipper: params.traceShipper
3784
4141
  };
@@ -4158,6 +4515,7 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4158
4515
  name: outerOperationId,
4159
4516
  parent: inheritedParent,
4160
4517
  eventId,
4518
+ ...identityFromContext(ctx),
4161
4519
  operationId: outerOperationId,
4162
4520
  attributes: [
4163
4521
  attrString("operation.name", operationName),
@@ -4166,9 +4524,6 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4166
4524
  attrString("ai.model.provider", modelInfoFromArgs.provider),
4167
4525
  attrString("ai.model.id", modelInfoFromArgs.modelId),
4168
4526
  attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
4169
- attrString("ai.telemetry.metadata.raindrop.eventName", ctx.eventName),
4170
- attrString("ai.telemetry.metadata.raindrop.ai.userId", ctx.userId),
4171
- attrString("ai.telemetry.metadata.raindrop.convoId", ctx.convoId),
4172
4527
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
4173
4528
  ...attrsFromHeaders(mergedArgs["headers"]),
4174
4529
  ...attrsFromSettings(mergedArgs),
@@ -4233,6 +4588,7 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4233
4588
  responseMessages,
4234
4589
  rootSpan,
4235
4590
  eventId,
4591
+ ...identityFromContext(ctx),
4236
4592
  telemetry,
4237
4593
  toolCalls,
4238
4594
  traceShipper: deps.traceShipper,
@@ -4285,6 +4641,11 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4285
4641
  input,
4286
4642
  output,
4287
4643
  model: finalModel,
4644
+ usage: {
4645
+ promptTokens: usage == null ? void 0 : usage.inputTokens,
4646
+ completionTokens: usage == null ? void 0 : usage.outputTokens
4647
+ },
4648
+ error,
4288
4649
  properties: patch.properties,
4289
4650
  featureFlags: patch.featureFlags,
4290
4651
  attachments: patch.attachments,
@@ -4368,6 +4729,7 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4368
4729
  name: outerOperationId,
4369
4730
  parent: inheritedParent,
4370
4731
  eventId,
4732
+ ...identityFromContext(ctx),
4371
4733
  operationId: outerOperationId,
4372
4734
  attributes: [
4373
4735
  attrString("operation.name", operationName),
@@ -4376,9 +4738,6 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4376
4738
  attrString("ai.model.provider", modelInfoFromArgs.provider),
4377
4739
  attrString("ai.model.id", modelInfoFromArgs.modelId),
4378
4740
  attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
4379
- attrString("ai.telemetry.metadata.raindrop.eventName", ctx.eventName),
4380
- attrString("ai.telemetry.metadata.raindrop.ai.userId", ctx.userId),
4381
- attrString("ai.telemetry.metadata.raindrop.convoId", ctx.convoId),
4382
4741
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
4383
4742
  ...attrsFromHeaders(mergedArgs["headers"]),
4384
4743
  ...attrsFromSettings(mergedArgs),
@@ -4443,6 +4802,7 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4443
4802
  responseMessages,
4444
4803
  rootSpan,
4445
4804
  eventId,
4805
+ ...identityFromContext(ctx),
4446
4806
  telemetry,
4447
4807
  toolCalls,
4448
4808
  traceShipper: deps.traceShipper,
@@ -4495,6 +4855,11 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4495
4855
  input,
4496
4856
  output,
4497
4857
  model: finalModel,
4858
+ usage: {
4859
+ promptTokens: usage == null ? void 0 : usage.inputTokens,
4860
+ completionTokens: usage == null ? void 0 : usage.outputTokens
4861
+ },
4862
+ error,
4498
4863
  properties: patch.properties,
4499
4864
  featureFlags: patch.featureFlags,
4500
4865
  attachments: patch.attachments,
@@ -4592,6 +4957,7 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
4592
4957
  name: "ai.toolCall",
4593
4958
  parent,
4594
4959
  eventId: ctx.eventId,
4960
+ ...identityFromContext(ctx.context),
4595
4961
  operationId: "ai.toolCall",
4596
4962
  attributes: [
4597
4963
  attrString("operation.name", operationName),
@@ -4826,8 +5192,13 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4826
5192
  ended = true;
4827
5193
  const msToFirstChunk = firstChunkMs !== void 0 ? firstChunkMs - startMs : void 0;
4828
5194
  const msToFinish = finishMs !== void 0 ? finishMs - startMs : void 0;
4829
- const inputTokens = extractNestedTokens(usage, "inputTokens");
4830
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5195
+ const usageMetrics = extractUsageMetricsFromUsage(
5196
+ usage,
5197
+ modelInfo.provider,
5198
+ providerMetadata
5199
+ );
5200
+ const finalResponseModelId = responseModelId != null ? responseModelId : modelInfo.modelId;
5201
+ const { inputTokens, outputTokens } = usageMetrics;
4831
5202
  const avgOutTokensPerSecond = msToFinish && outputTokens !== void 0 && msToFinish > 0 ? 1e3 * outputTokens / msToFinish : void 0;
4832
5203
  ctx.traceShipper.endSpan(span, {
4833
5204
  attributes: [
@@ -4839,7 +5210,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4839
5210
  safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
4840
5211
  ),
4841
5212
  attrString("ai.response.id", responseId),
4842
- attrString("ai.response.model", responseModelId),
5213
+ attrString("ai.response.model", finalResponseModelId),
4843
5214
  attrString("ai.response.timestamp", responseTimestampIso),
4844
5215
  attrString(
4845
5216
  "ai.response.providerMetadata",
@@ -4850,9 +5221,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4850
5221
  attrInt("ai.usage.outputTokens", outputTokens),
4851
5222
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
4852
5223
  attrString("gen_ai.response.id", responseId),
4853
- attrString("gen_ai.response.model", responseModelId),
4854
- attrInt("gen_ai.usage.input_tokens", inputTokens),
4855
- attrInt("gen_ai.usage.output_tokens", outputTokens),
5224
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
5225
+ ...buildModelUsageAttributes(usageMetrics),
4856
5226
  ...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
4857
5227
  ...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
4858
5228
  ...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
@@ -4952,20 +5322,20 @@ function startDoGenerateSpan(operationId, options, modelInfo, parent, ctx) {
4952
5322
  name: operationId,
4953
5323
  parent,
4954
5324
  eventId: ctx.eventId,
5325
+ ...identityFromContext(ctx.context),
4955
5326
  operationId,
4956
5327
  attributes: [
4957
5328
  attrString("operation.name", operationName),
4958
5329
  attrString("resource.name", resourceName),
4959
5330
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
4960
- attrString("ai.model.provider", modelInfo.provider),
5331
+ ...attrsFromModelProvider(modelInfo.provider),
4961
5332
  attrString("ai.model.id", modelInfo.modelId),
4962
5333
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
4963
5334
  attrString("ai.prompt.messages", promptJson),
4964
5335
  attrStringArray("ai.prompt.tools", toolsJson),
4965
5336
  attrString("ai.prompt.toolChoice", toolChoiceJson)
4966
5337
  ],
4967
- attrString("gen_ai.system", modelInfo.provider),
4968
- attrString("gen_ai.request.model", modelInfo.modelId),
5338
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
4969
5339
  ...attrsFromGenAiRequest(options),
4970
5340
  attrProviderOptions(options)
4971
5341
  ]
@@ -4998,8 +5368,12 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
4998
5368
  } else {
4999
5369
  responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
5000
5370
  }
5001
- const inputTokens = extractNestedTokens(usage, "inputTokens");
5002
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5371
+ const usageMetrics = extractUsageMetricsFromUsage(
5372
+ usage,
5373
+ modelInfo.provider,
5374
+ providerMetadata
5375
+ );
5376
+ const { inputTokens, outputTokens } = usageMetrics;
5003
5377
  ctx.traceShipper.endSpan(span, {
5004
5378
  attributes: [
5005
5379
  ...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
@@ -5018,9 +5392,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5018
5392
  attrInt("ai.usage.completionTokens", outputTokens),
5019
5393
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5020
5394
  attrString("gen_ai.response.id", responseId),
5021
- attrString("gen_ai.response.model", responseModelId),
5022
- attrInt("gen_ai.usage.input_tokens", inputTokens),
5023
- attrInt("gen_ai.usage.output_tokens", outputTokens)
5395
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
5396
+ ...buildModelUsageAttributes(usageMetrics)
5024
5397
  ]
5025
5398
  });
5026
5399
  }
@@ -5035,20 +5408,20 @@ function startDoStreamSpan(operationId, options, modelInfo, parent, ctx) {
5035
5408
  name: operationId,
5036
5409
  parent,
5037
5410
  eventId: ctx.eventId,
5411
+ ...identityFromContext(ctx.context),
5038
5412
  operationId,
5039
5413
  attributes: [
5040
5414
  attrString("operation.name", operationName),
5041
5415
  attrString("resource.name", resourceName),
5042
5416
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
5043
- attrString("ai.model.provider", modelInfo.provider),
5417
+ ...attrsFromModelProvider(modelInfo.provider),
5044
5418
  attrString("ai.model.id", modelInfo.modelId),
5045
5419
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
5046
5420
  attrString("ai.prompt.messages", promptJson),
5047
5421
  attrStringArray("ai.prompt.tools", toolsJson),
5048
5422
  attrString("ai.prompt.toolChoice", toolChoiceJson)
5049
5423
  ],
5050
- attrString("gen_ai.system", modelInfo.provider),
5051
- attrString("gen_ai.request.model", modelInfo.modelId),
5424
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
5052
5425
  ...attrsFromGenAiRequest(options),
5053
5426
  attrProviderOptions(options)
5054
5427
  ]
@@ -5113,13 +5486,6 @@ function mergeAttachments(...groups) {
5113
5486
  }
5114
5487
  return merged.length ? merged : void 0;
5115
5488
  }
5116
- function extractNestedTokens(usage, key) {
5117
- if (!isRecord(usage)) return void 0;
5118
- const val = usage[key];
5119
- if (typeof val === "number") return val;
5120
- if (isRecord(val) && typeof val["total"] === "number") return val["total"];
5121
- return void 0;
5122
- }
5123
5489
 
5124
5490
  // src/index.ts
5125
5491
  function eventMetadata(options) {
@@ -5295,6 +5661,9 @@ function createRaindropAISDK(opts) {
5295
5661
  const internal = traceShipper.startSpan({
5296
5662
  name: args.name,
5297
5663
  eventId: args.eventId,
5664
+ userId: args.userId,
5665
+ convoId: args.convoId,
5666
+ eventName: args.eventName,
5298
5667
  parent,
5299
5668
  operationId: args.operationId,
5300
5669
  attributes: attrs
@@ -5329,6 +5698,9 @@ function createRaindropAISDK(opts) {
5329
5698
  const internal = traceShipper.startSpan({
5330
5699
  name: args.name,
5331
5700
  eventId: args.eventId,
5701
+ userId: args.userId,
5702
+ convoId: args.convoId,
5703
+ eventName: args.eventName,
5332
5704
  parent,
5333
5705
  operationId: args.operationId,
5334
5706
  attributes: startAttrs,