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