@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.
@@ -4,7 +4,7 @@ var async_hooks = require('async_hooks');
4
4
 
5
5
  // src/index.workers.ts
6
6
 
7
- // ../core/dist/chunk-Y5LUB7OE.js
7
+ // ../core/dist/chunk-QNWZIOOY.js
8
8
  function normalizeFeatureFlags(input) {
9
9
  if (Array.isArray(input)) {
10
10
  return Object.fromEntries(input.map((name) => [name, "true"]));
@@ -447,19 +447,52 @@ function projectIdHeaders(projectId) {
447
447
  var SHUTDOWN_DEADLINE_MS = 1e4;
448
448
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
449
449
  function mergePatches(target, source) {
450
- var _a, _b, _c, _d, _e, _f;
450
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
451
451
  const out = { ...target, ...source };
452
452
  if (target.properties || source.properties) {
453
453
  out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
454
454
  }
455
+ if (target.usage || source.usage) {
456
+ out.usage = { ...(_c = target.usage) != null ? _c : {} };
457
+ if (((_d = source.usage) == null ? void 0 : _d.promptTokens) !== void 0) {
458
+ out.usage.promptTokens = source.usage.promptTokens;
459
+ }
460
+ if (((_e = source.usage) == null ? void 0 : _e.completionTokens) !== void 0) {
461
+ out.usage.completionTokens = source.usage.completionTokens;
462
+ }
463
+ }
464
+ if (source.error === void 0) {
465
+ out.error = target.error;
466
+ }
455
467
  if (target.featureFlags || source.featureFlags) {
456
- out.featureFlags = { ...(_c = target.featureFlags) != null ? _c : {}, ...(_d = source.featureFlags) != null ? _d : {} };
468
+ out.featureFlags = { ...(_f = target.featureFlags) != null ? _f : {}, ...(_g = source.featureFlags) != null ? _g : {} };
457
469
  }
458
470
  if (target.attachments || source.attachments) {
459
- out.attachments = [...(_e = target.attachments) != null ? _e : [], ...(_f = source.attachments) != null ? _f : []];
471
+ out.attachments = [...(_h = target.attachments) != null ? _h : [], ...(_i = source.attachments) != null ? _i : []];
460
472
  }
461
473
  return out;
462
474
  }
475
+ function isErrorLike(value) {
476
+ return value !== null && typeof value === "object";
477
+ }
478
+ function eventTelemetryProperties(patch) {
479
+ var _a, _b;
480
+ const properties = {};
481
+ if (((_a = patch.usage) == null ? void 0 : _a.promptTokens) !== void 0 && Number.isFinite(patch.usage.promptTokens)) {
482
+ properties["ai.usage.prompt_tokens"] = patch.usage.promptTokens;
483
+ }
484
+ if (((_b = patch.usage) == null ? void 0 : _b.completionTokens) !== void 0 && Number.isFinite(patch.usage.completionTokens)) {
485
+ properties["ai.usage.completion_tokens"] = patch.usage.completionTokens;
486
+ }
487
+ if (patch.error !== void 0 && patch.error !== null) {
488
+ const constructorName = patch.error instanceof Error && patch.error.constructor !== Error ? patch.error.constructor.name : void 0;
489
+ 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";
490
+ const errorMessage = patch.error instanceof Error ? patch.error.message : isErrorLike(patch.error) && typeof patch.error.message === "string" ? patch.error.message : String(patch.error);
491
+ properties["error.type"] = errorType;
492
+ properties["error.message"] = errorMessage;
493
+ }
494
+ return properties;
495
+ }
463
496
  var EventShipper = class {
464
497
  constructor(opts) {
465
498
  this.buffers = /* @__PURE__ */ new Map();
@@ -708,6 +741,11 @@ var EventShipper = class {
708
741
  return;
709
742
  }
710
743
  const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
744
+ let telemetryProperties = {};
745
+ try {
746
+ telemetryProperties = eventTelemetryProperties(accumulated);
747
+ } catch (e) {
748
+ }
711
749
  const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
712
750
  const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
713
751
  const payload = {
@@ -717,12 +755,13 @@ var EventShipper = class {
717
755
  timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
718
756
  ai_data: {
719
757
  input: accumulated.input,
720
- output: accumulated.output,
758
+ output: accumulated.error !== void 0 && accumulated.error !== null ? void 0 : accumulated.output,
721
759
  model: accumulated.model,
722
760
  convo_id: convoId
723
761
  },
724
762
  properties: {
725
763
  ...restProperties,
764
+ ...telemetryProperties,
726
765
  ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
727
766
  $context: this.context
728
767
  },
@@ -791,6 +830,193 @@ var EventShipper = class {
791
830
  }
792
831
  }
793
832
  };
833
+ var MODEL_USAGE_ATTRIBUTES = {
834
+ providerName: "gen_ai.provider.name",
835
+ requestModel: "gen_ai.request.model",
836
+ responseModel: "gen_ai.response.model",
837
+ inputTokens: "gen_ai.usage.input_tokens",
838
+ outputTokens: "gen_ai.usage.output_tokens",
839
+ reasoningTokens: "gen_ai.usage.reasoning_tokens",
840
+ cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
841
+ cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
842
+ nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
843
+ nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
844
+ reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
845
+ cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
846
+ cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
847
+ };
848
+ var MODEL_PROVIDER_NAMES = [
849
+ ["google.vertex", "google-vertex"],
850
+ ["vertex.anthropic", "google-vertex"],
851
+ ["amazon-bedrock", "amazon-bedrock"],
852
+ ["bedrock", "amazon-bedrock"],
853
+ ["anthropic", "anthropic"],
854
+ ["openai", "openai"],
855
+ ["google", "google"],
856
+ ["azure", "azure"],
857
+ ["openrouter", "openrouter"]
858
+ ];
859
+ function canonicalModelProvider(provider) {
860
+ var _a;
861
+ const normalizedProvider = provider.trim().toLowerCase();
862
+ if (normalizedProvider === "gateway") return "vercel";
863
+ const match = MODEL_PROVIDER_NAMES.find(
864
+ ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
865
+ );
866
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
867
+ }
868
+ function tokenCount(value) {
869
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
870
+ }
871
+ function exclusiveTokens({
872
+ explicit,
873
+ total,
874
+ parts,
875
+ semantics
876
+ }) {
877
+ if (explicit !== void 0) return explicit;
878
+ if (total === void 0) return void 0;
879
+ if (semantics === "exclusive") return total;
880
+ const observedParts = parts.filter((part) => part !== void 0 && part > 0);
881
+ if (semantics === void 0 && observedParts.length > 0) return void 0;
882
+ const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
883
+ return exclusive >= 0 ? exclusive : void 0;
884
+ }
885
+ function buildModelUsageAttributes(usage) {
886
+ const inputTokens = tokenCount(usage.inputTokens);
887
+ const outputTokens = tokenCount(usage.outputTokens);
888
+ const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
889
+ const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
890
+ const reasoningTokens = tokenCount(usage.reasoningTokens);
891
+ const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
892
+ const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
893
+ const nonCachedInputTokens = exclusiveTokens({
894
+ explicit: explicitNonCachedInputTokens,
895
+ total: inputTokens,
896
+ parts: [cacheReadInputTokens, cacheWriteInputTokens],
897
+ semantics: usage.inputTokenSemantics
898
+ });
899
+ const nonReasoningOutputTokens = exclusiveTokens({
900
+ explicit: explicitNonReasoningOutputTokens,
901
+ total: outputTokens,
902
+ parts: [reasoningTokens],
903
+ semantics: usage.outputTokenSemantics
904
+ });
905
+ const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
906
+ // backend consumes this complete raindrop.* set as one atomic billing-pool contract.
907
+ attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
908
+ attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
909
+ attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
910
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
911
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
912
+ ] : [];
913
+ return [
914
+ attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
915
+ attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
916
+ attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
917
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
918
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
919
+ ...exclusivePoolAttributes
920
+ ].filter((attribute) => attribute !== void 0);
921
+ }
922
+ var STRING_ALIASES = {
923
+ [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
924
+ };
925
+ var NUMBER_ALIASES = {
926
+ [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
927
+ "gen_ai.usage.prompt_tokens",
928
+ "ai.usage.prompt_tokens",
929
+ "ai.usage.promptTokens",
930
+ "ai.usage.input_tokens",
931
+ "ai.usage.inputTokens"
932
+ ],
933
+ [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
934
+ "gen_ai.usage.completion_tokens",
935
+ "ai.usage.completion_tokens",
936
+ "ai.usage.completionTokens",
937
+ "ai.usage.output_tokens",
938
+ "ai.usage.outputTokens"
939
+ ],
940
+ [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
941
+ "gen_ai.usage.reasoning.output_tokens",
942
+ "ai.usage.reasoningTokens",
943
+ "ai.usage.thoughts_tokens"
944
+ ],
945
+ [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
946
+ "gen_ai.usage.cache_read_tokens",
947
+ "gen_ai.usage.cache_read.input_tokens",
948
+ "ai.usage.cachedInputTokens",
949
+ "ai.usage.cached_tokens",
950
+ "ai.usage.cache_read_tokens",
951
+ "ai.usage.cache_read_input_tokens",
952
+ "ai.usage.cacheReadInputTokens"
953
+ ],
954
+ [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
955
+ "gen_ai.usage.cache_creation_input_tokens",
956
+ "gen_ai.usage.cache_creation.input_tokens",
957
+ "ai.usage.cacheWriteInputTokens",
958
+ "ai.usage.cache_creation_input_tokens",
959
+ "ai.usage.cacheCreationInputTokens"
960
+ ]
961
+ };
962
+ function hasAttribute(attributes, key) {
963
+ return attributes.some((attribute) => attribute.key === key);
964
+ }
965
+ function findStringAttribute(attributes, keys) {
966
+ return attributes.find(
967
+ (attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
968
+ );
969
+ }
970
+ function findNumberAttribute(attributes, keys) {
971
+ return attributes.find((attribute) => {
972
+ if (!keys.includes(attribute.key)) return false;
973
+ if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
974
+ return true;
975
+ }
976
+ const intValue = attribute.value.intValue;
977
+ return integerValue(intValue) !== void 0;
978
+ });
979
+ }
980
+ function integerValue(value) {
981
+ if (typeof value === "number") {
982
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
983
+ }
984
+ if (typeof value !== "string") return void 0;
985
+ const parsed = Number(value);
986
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
987
+ }
988
+ function appendAlias(attributes, target, source) {
989
+ if (!source || hasAttribute(attributes, target)) return attributes;
990
+ return [...attributes, { key: target, value: { ...source.value } }];
991
+ }
992
+ function appendProviderAlias(attributes) {
993
+ if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
994
+ const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
995
+ if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
996
+ const attribute = attrString(
997
+ MODEL_USAGE_ATTRIBUTES.providerName,
998
+ canonicalModelProvider(source.value.stringValue)
999
+ );
1000
+ return attribute ? [...attributes, attribute] : attributes;
1001
+ }
1002
+ function normalizeModelUsageSpan(span) {
1003
+ const original = span.attributes;
1004
+ if (!original || original.length === 0) return span;
1005
+ const responseModel = findStringAttribute(original, [
1006
+ MODEL_USAGE_ATTRIBUTES.responseModel,
1007
+ "ai.response.model"
1008
+ ]);
1009
+ if (!responseModel) return span;
1010
+ let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
1011
+ attributes = appendProviderAlias(attributes);
1012
+ for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
1013
+ attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
1014
+ }
1015
+ for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
1016
+ attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
1017
+ }
1018
+ return attributes === original ? span : { ...span, attributes };
1019
+ }
794
1020
  var DEFAULT_SECRET_KEY_NAMES = [
795
1021
  "apikey",
796
1022
  "apisecret",
@@ -880,6 +1106,13 @@ function redactJsonAttributeValue(key, value) {
880
1106
  if (scrubbedJson === json) return void 0;
881
1107
  return { stringValue: scrubbedJson };
882
1108
  }
1109
+ function identityAttrs(args) {
1110
+ return [
1111
+ attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
1112
+ attrString("ai.telemetry.metadata.raindrop.convoId", args.convoId),
1113
+ attrString("ai.telemetry.metadata.raindrop.eventName", args.eventName)
1114
+ ];
1115
+ }
883
1116
  function applyOtelSpanAttributeLimit(limit) {
884
1117
  var _a, _b;
885
1118
  try {
@@ -984,6 +1217,10 @@ var TraceShipper = class {
984
1217
  return null;
985
1218
  }
986
1219
  }
1220
+ try {
1221
+ current = normalizeModelUsageSpan(current);
1222
+ } catch (e) {
1223
+ }
987
1224
  if (!this.disableDefaultRedaction) {
988
1225
  current = defaultTransformSpan(current);
989
1226
  }
@@ -1004,6 +1241,7 @@ var TraceShipper = class {
1004
1241
  const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
1005
1242
  const attrs = [
1006
1243
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1244
+ ...identityAttrs(args),
1007
1245
  attrString("ai.operationId", args.operationId)
1008
1246
  ];
1009
1247
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
@@ -1059,7 +1297,8 @@ var TraceShipper = class {
1059
1297
  var _a;
1060
1298
  const ids = createSpanIds(args.parent);
1061
1299
  const attrs = [
1062
- attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId)
1300
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1301
+ ...identityAttrs(args)
1063
1302
  ];
1064
1303
  if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1065
1304
  const otlp = buildOtlpSpan({
@@ -1341,7 +1580,7 @@ installTracingSuppressionHook();
1341
1580
  // package.json
1342
1581
  var package_default = {
1343
1582
  name: "@raindrop-ai/ai-sdk",
1344
- version: "0.1.1"};
1583
+ version: "0.2.1"};
1345
1584
 
1346
1585
  // src/internal/version.ts
1347
1586
  var libraryName = package_default.name;
@@ -2038,6 +2277,15 @@ function attrsFromHeaders(headers) {
2038
2277
  if (!isRecord(headers)) return [];
2039
2278
  return Object.entries(headers).filter(([, v]) => typeof v === "string").map(([k, v]) => attrString(`ai.request.headers.${k}`, v));
2040
2279
  }
2280
+ function attrsFromModelProvider(provider) {
2281
+ if (typeof provider !== "string" || provider.length === 0) return [];
2282
+ const providerName = canonicalModelProvider(provider);
2283
+ return [
2284
+ attrString("ai.model.provider", provider),
2285
+ attrString(MODEL_USAGE_ATTRIBUTES.providerName, providerName),
2286
+ attrString("gen_ai.system", provider)
2287
+ ];
2288
+ }
2041
2289
  function attrsFromSettings(args) {
2042
2290
  if (!isRecord(args)) return [];
2043
2291
  const result = [];
@@ -2220,6 +2468,126 @@ function runWithParentToolContext(ctx, fn) {
2220
2468
  return getStorage2().run(ctx, fn);
2221
2469
  }
2222
2470
 
2471
+ // src/internal/usage.ts
2472
+ function firstTokenCount(...values) {
2473
+ for (const value of values) {
2474
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
2475
+ return value;
2476
+ }
2477
+ }
2478
+ return void 0;
2479
+ }
2480
+ function flatUsageSemantics(provider) {
2481
+ const normalizedProvider = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
2482
+ if (normalizedProvider === "anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("anthropic.")) || normalizedProvider === "vertex.anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("vertex.anthropic."))) {
2483
+ return {
2484
+ inputTokenSemantics: "exclusive",
2485
+ outputTokenSemantics: "total"
2486
+ };
2487
+ }
2488
+ if (normalizedProvider === "openai" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("openai.")) || normalizedProvider === "azure" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("azure."))) {
2489
+ return {
2490
+ inputTokenSemantics: "total",
2491
+ outputTokenSemantics: "total"
2492
+ };
2493
+ }
2494
+ if (normalizedProvider === "google" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("google."))) {
2495
+ return {
2496
+ inputTokenSemantics: "total",
2497
+ // Google v5 reports candidate output and thoughts separately.
2498
+ outputTokenSemantics: "exclusive"
2499
+ };
2500
+ }
2501
+ return {};
2502
+ }
2503
+ var CACHE_WRITE_METADATA_KEYS = [
2504
+ ["anthropic", "cacheCreationInputTokens"],
2505
+ ["openai", "cacheWriteTokens"],
2506
+ ["bedrock", "cacheWriteInputTokens"]
2507
+ ];
2508
+ function cacheWriteTokensFromProviderMetadata(providerMetadata) {
2509
+ if (!isRecord(providerMetadata)) return void 0;
2510
+ return firstTokenCount(
2511
+ ...CACHE_WRITE_METADATA_KEYS.flatMap(([namespace, key]) => {
2512
+ const scope = providerMetadata[namespace];
2513
+ if (!isRecord(scope)) return [];
2514
+ const usage = scope["usage"];
2515
+ return [scope[key], isRecord(usage) ? usage[key] : void 0];
2516
+ })
2517
+ );
2518
+ }
2519
+ function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
2520
+ if (!isRecord(usage)) return {};
2521
+ const inputTokenValue = usage["inputTokens"];
2522
+ const outputTokenValue = usage["outputTokens"];
2523
+ const inputTokenDetails = usage["inputTokenDetails"];
2524
+ const outputTokenDetails = usage["outputTokenDetails"];
2525
+ const hasStructuredUsage = isRecord(inputTokenValue) || isRecord(outputTokenValue) || isRecord(inputTokenDetails) || isRecord(outputTokenDetails);
2526
+ const inputTokens = firstTokenCount(
2527
+ isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
2528
+ inputTokenValue,
2529
+ usage["promptTokens"],
2530
+ usage["prompt_tokens"]
2531
+ );
2532
+ const outputTokens = firstTokenCount(
2533
+ isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
2534
+ outputTokenValue,
2535
+ usage["completionTokens"],
2536
+ usage["completion_tokens"]
2537
+ );
2538
+ const reasoningTokens = firstTokenCount(
2539
+ isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
2540
+ isRecord(outputTokenDetails) ? outputTokenDetails["reasoningTokens"] : void 0,
2541
+ usage["reasoningTokens"],
2542
+ usage["completionReasoningTokens"],
2543
+ usage["completion_reasoning_tokens"],
2544
+ usage["reasoning_tokens"],
2545
+ usage["thinkingTokens"],
2546
+ usage["thinking_tokens"]
2547
+ );
2548
+ const cacheReadInputTokens = firstTokenCount(
2549
+ isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
2550
+ isRecord(inputTokenDetails) ? inputTokenDetails["cacheReadTokens"] : void 0,
2551
+ usage["cachedInputTokens"],
2552
+ usage["promptCachedTokens"],
2553
+ usage["prompt_cached_tokens"]
2554
+ );
2555
+ const cacheWriteInputTokens = firstTokenCount(
2556
+ isRecord(inputTokenValue) ? inputTokenValue["cacheWrite"] : void 0,
2557
+ isRecord(inputTokenDetails) ? inputTokenDetails["cacheWriteTokens"] : void 0,
2558
+ usage["cacheWriteInputTokens"],
2559
+ usage["cacheCreationInputTokens"],
2560
+ usage["cache_creation_input_tokens"],
2561
+ cacheWriteTokensFromProviderMetadata(providerMetadata)
2562
+ );
2563
+ const nonCachedInputTokens = firstTokenCount(
2564
+ isRecord(inputTokenValue) ? inputTokenValue["noCache"] : void 0,
2565
+ isRecord(inputTokenDetails) ? inputTokenDetails["noCacheTokens"] : void 0
2566
+ );
2567
+ const nonReasoningOutputTokens = firstTokenCount(
2568
+ isRecord(outputTokenValue) ? outputTokenValue["text"] : void 0,
2569
+ isRecord(outputTokenDetails) ? outputTokenDetails["textTokens"] : void 0
2570
+ );
2571
+ const totalTokens = firstTokenCount(
2572
+ usage["totalTokens"],
2573
+ usage["tokens"],
2574
+ usage["total_tokens"],
2575
+ inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
2576
+ );
2577
+ return {
2578
+ inputTokens,
2579
+ outputTokens,
2580
+ totalTokens,
2581
+ nonCachedInputTokens,
2582
+ nonReasoningOutputTokens,
2583
+ reasoningTokens,
2584
+ cacheReadInputTokens,
2585
+ cachedInputTokens: cacheReadInputTokens,
2586
+ cacheWriteInputTokens,
2587
+ ...hasStructuredUsage ? {} : flatUsageSemantics(provider)
2588
+ };
2589
+ }
2590
+
2223
2591
  // src/internal/raindrop-telemetry-integration.ts
2224
2592
  function hasUnresolvedToolApproval(event) {
2225
2593
  var _a;
@@ -2276,7 +2644,7 @@ var RaindropTelemetryIntegration = class {
2276
2644
  };
2277
2645
  // ── onStart ─────────────────────────────────────────────────────────────
2278
2646
  this.onStart = (event) => {
2279
- var _a, _b, _c, _d, _e;
2647
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2280
2648
  if (event.isEnabled === false) return;
2281
2649
  const isEmbed = event.operationId === "ai.embed" || event.operationId === "ai.embedMany";
2282
2650
  const recordInputs = event.recordInputs !== false;
@@ -2286,15 +2654,20 @@ var RaindropTelemetryIntegration = class {
2286
2654
  const callContextMetadata = getCurrentRaindropCallMetadata();
2287
2655
  const metadata = eventMetadata2 != null ? eventMetadata2 : callContextMetadata == null ? void 0 : callContextMetadata.rawMetadata;
2288
2656
  const callMeta = this.extractRaindropMetadata(metadata);
2657
+ const identity = {
2658
+ userId: (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId,
2659
+ convoId: (_d = callMeta.convoId) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.convoId,
2660
+ eventName: (_f = callMeta.eventName) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.eventName
2661
+ };
2289
2662
  const inherited = getContextManager().getParentSpanIds();
2290
2663
  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;
2291
2664
  const explicitEventId = callMeta.eventId && !eventIdGenerated ? callMeta.eventId : void 0;
2292
- 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();
2665
+ 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();
2293
2666
  const inheritedParent = inherited && inherited.eventId === eventId ? { traceIdB64: inherited.traceIdB64, spanIdB64: inherited.spanIdB64 } : void 0;
2294
2667
  const { operationName, resourceName } = opName(event.operationId, functionId);
2295
2668
  const parentToolContext = !isEmbed && this.subagentWrapping ? getCurrentParentToolContext() : void 0;
2296
2669
  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;
2297
- const subagentName = (_e = parentToolContext == null ? void 0 : parentToolContext.toolName) != null ? _e : metadataSubagentName;
2670
+ const subagentName = (_k = parentToolContext == null ? void 0 : parentToolContext.toolName) != null ? _k : metadataSubagentName;
2298
2671
  let subagentToolCallSpan;
2299
2672
  let rootParentOverride;
2300
2673
  if (subagentName && this.sendTraces) {
@@ -2307,6 +2680,7 @@ var RaindropTelemetryIntegration = class {
2307
2680
  name: subagentName,
2308
2681
  parent: inheritedParent,
2309
2682
  eventId,
2683
+ ...identity,
2310
2684
  operationId: "ai.toolCall",
2311
2685
  attributes: [
2312
2686
  attrString("operation.name", "ai.toolCall"),
@@ -2323,6 +2697,7 @@ var RaindropTelemetryIntegration = class {
2323
2697
  name: "agent.subagent",
2324
2698
  parent: subagentParentRef,
2325
2699
  eventId,
2700
+ ...identity,
2326
2701
  operationId: "agent.subagent",
2327
2702
  attributes: [
2328
2703
  attrString("operation.name", "agent.subagent"),
@@ -2350,6 +2725,7 @@ var RaindropTelemetryIntegration = class {
2350
2725
  name: event.operationId,
2351
2726
  parent: rootParentOverride != null ? rootParentOverride : inheritedParent,
2352
2727
  eventId,
2728
+ ...identity,
2353
2729
  operationId: event.operationId,
2354
2730
  attributes: [
2355
2731
  attrString("operation.name", operationName),
@@ -2357,13 +2733,14 @@ var RaindropTelemetryIntegration = class {
2357
2733
  attrString("ai.telemetry.functionId", functionId),
2358
2734
  attrString("ai.model.provider", event.provider),
2359
2735
  attrString("ai.model.id", event.modelId),
2360
- // Filter out raindrop.eventId from metadata attrs since TraceShipper
2361
- // already sets it via the eventId arg. Without this, eventMetadata()'s
2362
- // auto-generated ID would duplicate and override the resolved one.
2736
+ // Filter out identity keys (eventId/userId/convoId/eventName) from
2737
+ // metadata attrs since TraceShipper already stamps them via dedicated
2738
+ // args. Without this, eventMetadata()'s auto-generated ID would
2739
+ // duplicate and override the resolved one.
2363
2740
  ...attrsFromTelemetryMetadata(
2364
2741
  metadata ? Object.fromEntries(
2365
2742
  Object.entries(metadata).filter(
2366
- ([k]) => k !== "raindrop.eventId" && k !== "raindrop.internal.eventIdGenerated"
2743
+ ([k]) => k !== "raindrop.eventId" && k !== "raindrop.internal.eventIdGenerated" && k !== "raindrop.userId" && k !== "raindrop.convoId" && k !== "raindrop.eventName"
2367
2744
  )
2368
2745
  ) : void 0
2369
2746
  ),
@@ -2375,10 +2752,13 @@ var RaindropTelemetryIntegration = class {
2375
2752
  this.callStates.set(event.callId, {
2376
2753
  operationId: event.operationId,
2377
2754
  eventId,
2755
+ identity,
2378
2756
  rootSpan,
2379
2757
  rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
2380
2758
  stepSpan: void 0,
2381
2759
  stepParent: void 0,
2760
+ stepProvider: void 0,
2761
+ stepModelId: void 0,
2382
2762
  toolSpans: /* @__PURE__ */ new Map(),
2383
2763
  embedSpans: /* @__PURE__ */ new Map(),
2384
2764
  parentContextToolCallIds: /* @__PURE__ */ new Set(),
@@ -2426,20 +2806,22 @@ var RaindropTelemetryIntegration = class {
2426
2806
  name: stepOperationId,
2427
2807
  parent: state.rootParent,
2428
2808
  eventId: state.eventId,
2809
+ ...state.identity,
2429
2810
  operationId: stepOperationId,
2430
2811
  attributes: [
2431
2812
  attrString("operation.name", operationName),
2432
2813
  attrString("resource.name", resourceName),
2433
2814
  attrString("ai.telemetry.functionId", state.functionId),
2434
- attrString("ai.model.provider", event.provider),
2815
+ ...attrsFromModelProvider(event.provider),
2435
2816
  attrString("ai.model.id", event.modelId),
2436
- attrString("gen_ai.system", event.provider),
2437
- attrString("gen_ai.request.model", event.modelId),
2817
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
2438
2818
  ...inputAttrs
2439
2819
  ]
2440
2820
  });
2441
2821
  state.stepSpan = stepSpan;
2442
2822
  state.stepParent = this.spanParentRef(stepSpan);
2823
+ state.stepProvider = event.provider;
2824
+ state.stepModelId = event.modelId;
2443
2825
  };
2444
2826
  this.onToolExecutionStart = (event) => this.toolExecutionStart(event);
2445
2827
  this.onToolExecutionEnd = (event) => this.toolExecutionEnd(event);
@@ -2490,23 +2872,24 @@ var RaindropTelemetryIntegration = class {
2490
2872
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2491
2873
  const state = this.getState(event.callId);
2492
2874
  if (!(state == null ? void 0 : state.stepSpan)) return;
2875
+ const responseModelId = (_b = (_a = event.response) == null ? void 0 : _a.modelId) != null ? _b : state.stepModelId;
2493
2876
  const outputAttrs = [];
2494
2877
  if (state.recordOutputs) {
2495
2878
  outputAttrs.push(
2496
2879
  attrString("ai.response.finishReason", event.finishReason),
2497
- attrString("ai.response.text", capText2((_a = event.text) != null ? _a : void 0)),
2498
- attrString("ai.response.id", (_b = event.response) == null ? void 0 : _b.id),
2499
- attrString("ai.response.model", (_c = event.response) == null ? void 0 : _c.modelId),
2880
+ attrString("ai.response.text", capText2((_c = event.text) != null ? _c : void 0)),
2881
+ attrString("ai.response.id", (_d = event.response) == null ? void 0 : _d.id),
2882
+ attrString("ai.response.model", responseModelId),
2500
2883
  attrString(
2501
2884
  "ai.response.timestamp",
2502
- ((_d = event.response) == null ? void 0 : _d.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_e = event.response) == null ? void 0 : _e.timestamp
2885
+ ((_e = event.response) == null ? void 0 : _e.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_f = event.response) == null ? void 0 : _f.timestamp
2503
2886
  ),
2504
2887
  attrString(
2505
2888
  "ai.response.providerMetadata",
2506
2889
  event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
2507
2890
  )
2508
2891
  );
2509
- if (((_f = event.toolCalls) == null ? void 0 : _f.length) > 0) {
2892
+ if (((_g = event.toolCalls) == null ? void 0 : _g.length) > 0) {
2510
2893
  outputAttrs.push(
2511
2894
  attrString(
2512
2895
  "ai.response.toolCalls",
@@ -2520,7 +2903,7 @@ var RaindropTelemetryIntegration = class {
2520
2903
  )
2521
2904
  );
2522
2905
  }
2523
- if (((_g = event.reasoning) == null ? void 0 : _g.length) > 0) {
2906
+ if (((_h = event.reasoning) == null ? void 0 : _h.length) > 0) {
2524
2907
  const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
2525
2908
  if (reasoningText) {
2526
2909
  outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
@@ -2529,25 +2912,31 @@ var RaindropTelemetryIntegration = class {
2529
2912
  }
2530
2913
  outputAttrs.push(
2531
2914
  attrStringArray("gen_ai.response.finish_reasons", [event.finishReason]),
2532
- attrString("gen_ai.response.id", (_h = event.response) == null ? void 0 : _h.id),
2533
- attrString("gen_ai.response.model", (_i = event.response) == null ? void 0 : _i.modelId)
2915
+ attrString("gen_ai.response.id", (_i = event.response) == null ? void 0 : _i.id),
2916
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId)
2534
2917
  );
2535
2918
  const usage = event.usage;
2536
2919
  if (usage) {
2920
+ const usageMetrics = extractUsageMetricsFromUsage(
2921
+ usage,
2922
+ state.stepProvider,
2923
+ event.providerMetadata
2924
+ );
2537
2925
  outputAttrs.push(
2538
- attrInt("ai.usage.inputTokens", usage.inputTokens),
2539
- attrInt("ai.usage.outputTokens", usage.outputTokens),
2540
- attrInt("ai.usage.totalTokens", usage.totalTokens),
2541
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
2542
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens),
2543
- attrInt("gen_ai.usage.input_tokens", usage.inputTokens),
2544
- attrInt("gen_ai.usage.output_tokens", usage.outputTokens)
2926
+ attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
2927
+ attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
2928
+ attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
2929
+ attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
2930
+ attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens),
2931
+ ...buildModelUsageAttributes(usageMetrics)
2545
2932
  );
2546
2933
  }
2547
2934
  this.emitProviderExecutedToolSpans(event, state);
2548
2935
  this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
2549
2936
  state.stepSpan = void 0;
2550
2937
  state.stepParent = void 0;
2938
+ state.stepProvider = void 0;
2939
+ state.stepModelId = void 0;
2551
2940
  };
2552
2941
  // ── onEmbedStart ────────────────────────────────────────────────────────
2553
2942
  this.onEmbedStart = (event) => {
@@ -2559,6 +2948,7 @@ var RaindropTelemetryIntegration = class {
2559
2948
  name: event.operationId,
2560
2949
  parent: state.rootParent,
2561
2950
  eventId: state.eventId,
2951
+ ...state.identity,
2562
2952
  operationId: event.operationId,
2563
2953
  attributes: [
2564
2954
  attrString("operation.name", operationName),
@@ -2621,6 +3011,8 @@ var RaindropTelemetryIntegration = class {
2621
3011
  const actualError = (_a = event.error) != null ? _a : error;
2622
3012
  if (state.stepSpan) {
2623
3013
  this.traceShipper.endSpan(state.stepSpan, { error: actualError });
3014
+ state.stepProvider = void 0;
3015
+ state.stepModelId = void 0;
2624
3016
  }
2625
3017
  for (const embedSpan of state.embedSpans.values()) {
2626
3018
  this.traceShipper.endSpan(embedSpan, { error: actualError });
@@ -2664,6 +3056,8 @@ var RaindropTelemetryIntegration = class {
2664
3056
  this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
2665
3057
  state.stepSpan = void 0;
2666
3058
  state.stepParent = void 0;
3059
+ state.stepProvider = void 0;
3060
+ state.stepModelId = void 0;
2667
3061
  }
2668
3062
  for (const embedSpan of state.embedSpans.values()) {
2669
3063
  this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
@@ -2825,6 +3219,7 @@ var RaindropTelemetryIntegration = class {
2825
3219
  name: "ai.toolCall",
2826
3220
  parent: state.stepParent,
2827
3221
  eventId: state.eventId,
3222
+ ...state.identity,
2828
3223
  operationId: "ai.toolCall",
2829
3224
  attributes: [
2830
3225
  attrString("operation.name", operationName),
@@ -2902,6 +3297,7 @@ var RaindropTelemetryIntegration = class {
2902
3297
  name: "ai.toolCall",
2903
3298
  parent: state.stepParent,
2904
3299
  eventId: state.eventId,
3300
+ ...state.identity,
2905
3301
  operationId: "ai.toolCall",
2906
3302
  attributes: [
2907
3303
  attrString("operation.name", operationName),
@@ -2961,12 +3357,13 @@ var RaindropTelemetryIntegration = class {
2961
3357
  }
2962
3358
  const usage = (_d = event.totalUsage) != null ? _d : event.usage;
2963
3359
  if (usage) {
3360
+ const usageMetrics = extractUsageMetricsFromUsage(usage);
2964
3361
  outputAttrs.push(
2965
- attrInt("ai.usage.inputTokens", usage.inputTokens),
2966
- attrInt("ai.usage.outputTokens", usage.outputTokens),
2967
- attrInt("ai.usage.totalTokens", usage.totalTokens),
2968
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
2969
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens)
3362
+ attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
3363
+ attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
3364
+ attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
3365
+ attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
3366
+ attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens)
2970
3367
  );
2971
3368
  }
2972
3369
  outputAttrs.push(attrInt("ai.toolCall.count", state.toolCallCount));
@@ -3419,14 +3816,6 @@ function runWithParentSpanContextSync(ctx, fn) {
3419
3816
  function isAsyncIterable(value) {
3420
3817
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
3421
3818
  }
3422
- function firstFiniteNumber(...values) {
3423
- for (const value of values) {
3424
- if (typeof value === "number" && Number.isFinite(value)) {
3425
- return value;
3426
- }
3427
- }
3428
- return void 0;
3429
- }
3430
3819
  function resolveUsageRecord(result) {
3431
3820
  if (!isRecord(result)) return void 0;
3432
3821
  let usage;
@@ -3442,50 +3831,7 @@ function resolveUsageRecord(result) {
3442
3831
  return isRecord(usage) ? usage : void 0;
3443
3832
  }
3444
3833
  function extractUsageMetrics(result) {
3445
- const usage = resolveUsageRecord(result);
3446
- if (!usage) return {};
3447
- const inputTokenValue = usage["inputTokens"];
3448
- const outputTokenValue = usage["outputTokens"];
3449
- const inputTokens = firstFiniteNumber(
3450
- isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
3451
- inputTokenValue,
3452
- usage["promptTokens"],
3453
- usage["prompt_tokens"]
3454
- );
3455
- const outputTokens = firstFiniteNumber(
3456
- isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
3457
- outputTokenValue,
3458
- usage["completionTokens"],
3459
- usage["completion_tokens"]
3460
- );
3461
- const totalTokens = firstFiniteNumber(
3462
- usage["totalTokens"],
3463
- usage["tokens"],
3464
- usage["total_tokens"],
3465
- inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
3466
- );
3467
- const reasoningTokens = firstFiniteNumber(
3468
- isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
3469
- usage["reasoningTokens"],
3470
- usage["completionReasoningTokens"],
3471
- usage["completion_reasoning_tokens"],
3472
- usage["reasoning_tokens"],
3473
- usage["thinkingTokens"],
3474
- usage["thinking_tokens"]
3475
- );
3476
- const cachedInputTokens = firstFiniteNumber(
3477
- isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
3478
- usage["cachedInputTokens"],
3479
- usage["promptCachedTokens"],
3480
- usage["prompt_cached_tokens"]
3481
- );
3482
- return {
3483
- inputTokens,
3484
- outputTokens,
3485
- totalTokens,
3486
- reasoningTokens,
3487
- cachedInputTokens
3488
- };
3834
+ return extractUsageMetricsFromUsage(resolveUsageRecord(result));
3489
3835
  }
3490
3836
  function isObjectOperation(operation) {
3491
3837
  return operation === "generateObject" || operation === "streamObject";
@@ -3569,6 +3915,9 @@ function teeStreamObjectBaseStream(result) {
3569
3915
  } catch (e) {
3570
3916
  }
3571
3917
  }
3918
+ function identityFromContext(ctx) {
3919
+ return { userId: ctx.userId, convoId: ctx.convoId, eventName: ctx.eventName };
3920
+ }
3572
3921
  function setupOperation(params) {
3573
3922
  var _a, _b, _c;
3574
3923
  const {
@@ -3600,6 +3949,7 @@ function setupOperation(params) {
3600
3949
  name: outerOperationId,
3601
3950
  parent: inheritedParent,
3602
3951
  eventId,
3952
+ ...identityFromContext(mergedCtx),
3603
3953
  operationId: outerOperationId,
3604
3954
  attributes: [
3605
3955
  attrString("operation.name", operationName),
@@ -3608,9 +3958,6 @@ function setupOperation(params) {
3608
3958
  attrString("ai.model.provider", modelInfoFromArgs.provider),
3609
3959
  attrString("ai.model.id", modelInfoFromArgs.modelId),
3610
3960
  attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
3611
- attrString("ai.telemetry.metadata.raindrop.eventName", mergedCtx.eventName),
3612
- attrString("ai.telemetry.metadata.raindrop.ai.userId", mergedCtx.userId),
3613
- attrString("ai.telemetry.metadata.raindrop.convoId", mergedCtx.convoId),
3614
3961
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
3615
3962
  ...attrsFromHeaders(isRecord(arg) ? arg["headers"] : void 0),
3616
3963
  ...attrsFromSettings(arg),
@@ -3700,6 +4047,7 @@ function createFinalize(params) {
3700
4047
  responseMessages,
3701
4048
  rootSpan: setup.rootSpan,
3702
4049
  eventId: setup.eventId,
4050
+ ...identityFromContext(setup.ctx),
3703
4051
  telemetry: setup.telemetry,
3704
4052
  toolCalls: setup.toolCalls,
3705
4053
  traceShipper,
@@ -3738,6 +4086,11 @@ function createFinalize(params) {
3738
4086
  input,
3739
4087
  output,
3740
4088
  model: finalModel,
4089
+ usage: {
4090
+ promptTokens: usage == null ? void 0 : usage.inputTokens,
4091
+ completionTokens: usage == null ? void 0 : usage.outputTokens
4092
+ },
4093
+ error,
3741
4094
  properties: patch.properties,
3742
4095
  featureFlags: patch.featureFlags,
3743
4096
  attachments: patch.attachments,
@@ -3772,6 +4125,7 @@ function startToolSpan(toolCall, rootSpan, ctx, startTimeUnixNano) {
3772
4125
  name: "ai.toolCall",
3773
4126
  parent: { traceIdB64: rootSpan.ids.traceIdB64, spanIdB64: rootSpan.ids.spanIdB64 },
3774
4127
  eventId: ctx.eventId,
4128
+ ...identityFromContext(ctx),
3775
4129
  operationId: "ai.toolCall",
3776
4130
  attributes: [
3777
4131
  attrString("operation.name", operationName),
@@ -3809,6 +4163,9 @@ function emitTranscriptToolCallSpans(params) {
3809
4163
  }
3810
4164
  const ctx = {
3811
4165
  eventId: params.eventId,
4166
+ userId: params.userId,
4167
+ convoId: params.convoId,
4168
+ eventName: params.eventName,
3812
4169
  telemetry: params.telemetry,
3813
4170
  traceShipper: params.traceShipper
3814
4171
  };
@@ -4188,6 +4545,7 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4188
4545
  name: outerOperationId,
4189
4546
  parent: inheritedParent,
4190
4547
  eventId,
4548
+ ...identityFromContext(ctx),
4191
4549
  operationId: outerOperationId,
4192
4550
  attributes: [
4193
4551
  attrString("operation.name", operationName),
@@ -4196,9 +4554,6 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4196
4554
  attrString("ai.model.provider", modelInfoFromArgs.provider),
4197
4555
  attrString("ai.model.id", modelInfoFromArgs.modelId),
4198
4556
  attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
4199
- attrString("ai.telemetry.metadata.raindrop.eventName", ctx.eventName),
4200
- attrString("ai.telemetry.metadata.raindrop.ai.userId", ctx.userId),
4201
- attrString("ai.telemetry.metadata.raindrop.convoId", ctx.convoId),
4202
4557
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
4203
4558
  ...attrsFromHeaders(mergedArgs["headers"]),
4204
4559
  ...attrsFromSettings(mergedArgs),
@@ -4263,6 +4618,7 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4263
4618
  responseMessages,
4264
4619
  rootSpan,
4265
4620
  eventId,
4621
+ ...identityFromContext(ctx),
4266
4622
  telemetry,
4267
4623
  toolCalls,
4268
4624
  traceShipper: deps.traceShipper,
@@ -4315,6 +4671,11 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4315
4671
  input,
4316
4672
  output,
4317
4673
  model: finalModel,
4674
+ usage: {
4675
+ promptTokens: usage == null ? void 0 : usage.inputTokens,
4676
+ completionTokens: usage == null ? void 0 : usage.outputTokens
4677
+ },
4678
+ error,
4318
4679
  properties: patch.properties,
4319
4680
  featureFlags: patch.featureFlags,
4320
4681
  attachments: patch.attachments,
@@ -4398,6 +4759,7 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4398
4759
  name: outerOperationId,
4399
4760
  parent: inheritedParent,
4400
4761
  eventId,
4762
+ ...identityFromContext(ctx),
4401
4763
  operationId: outerOperationId,
4402
4764
  attributes: [
4403
4765
  attrString("operation.name", operationName),
@@ -4406,9 +4768,6 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4406
4768
  attrString("ai.model.provider", modelInfoFromArgs.provider),
4407
4769
  attrString("ai.model.id", modelInfoFromArgs.modelId),
4408
4770
  attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
4409
- attrString("ai.telemetry.metadata.raindrop.eventName", ctx.eventName),
4410
- attrString("ai.telemetry.metadata.raindrop.ai.userId", ctx.userId),
4411
- attrString("ai.telemetry.metadata.raindrop.convoId", ctx.convoId),
4412
4771
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
4413
4772
  ...attrsFromHeaders(mergedArgs["headers"]),
4414
4773
  ...attrsFromSettings(mergedArgs),
@@ -4473,6 +4832,7 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4473
4832
  responseMessages,
4474
4833
  rootSpan,
4475
4834
  eventId,
4835
+ ...identityFromContext(ctx),
4476
4836
  telemetry,
4477
4837
  toolCalls,
4478
4838
  traceShipper: deps.traceShipper,
@@ -4525,6 +4885,11 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4525
4885
  input,
4526
4886
  output,
4527
4887
  model: finalModel,
4888
+ usage: {
4889
+ promptTokens: usage == null ? void 0 : usage.inputTokens,
4890
+ completionTokens: usage == null ? void 0 : usage.outputTokens
4891
+ },
4892
+ error,
4528
4893
  properties: patch.properties,
4529
4894
  featureFlags: patch.featureFlags,
4530
4895
  attachments: patch.attachments,
@@ -4622,6 +4987,7 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
4622
4987
  name: "ai.toolCall",
4623
4988
  parent,
4624
4989
  eventId: ctx.eventId,
4990
+ ...identityFromContext(ctx.context),
4625
4991
  operationId: "ai.toolCall",
4626
4992
  attributes: [
4627
4993
  attrString("operation.name", operationName),
@@ -4856,8 +5222,13 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4856
5222
  ended = true;
4857
5223
  const msToFirstChunk = firstChunkMs !== void 0 ? firstChunkMs - startMs : void 0;
4858
5224
  const msToFinish = finishMs !== void 0 ? finishMs - startMs : void 0;
4859
- const inputTokens = extractNestedTokens(usage, "inputTokens");
4860
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5225
+ const usageMetrics = extractUsageMetricsFromUsage(
5226
+ usage,
5227
+ modelInfo.provider,
5228
+ providerMetadata
5229
+ );
5230
+ const finalResponseModelId = responseModelId != null ? responseModelId : modelInfo.modelId;
5231
+ const { inputTokens, outputTokens } = usageMetrics;
4861
5232
  const avgOutTokensPerSecond = msToFinish && outputTokens !== void 0 && msToFinish > 0 ? 1e3 * outputTokens / msToFinish : void 0;
4862
5233
  ctx.traceShipper.endSpan(span, {
4863
5234
  attributes: [
@@ -4869,7 +5240,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4869
5240
  safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
4870
5241
  ),
4871
5242
  attrString("ai.response.id", responseId),
4872
- attrString("ai.response.model", responseModelId),
5243
+ attrString("ai.response.model", finalResponseModelId),
4873
5244
  attrString("ai.response.timestamp", responseTimestampIso),
4874
5245
  attrString(
4875
5246
  "ai.response.providerMetadata",
@@ -4880,9 +5251,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4880
5251
  attrInt("ai.usage.outputTokens", outputTokens),
4881
5252
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
4882
5253
  attrString("gen_ai.response.id", responseId),
4883
- attrString("gen_ai.response.model", responseModelId),
4884
- attrInt("gen_ai.usage.input_tokens", inputTokens),
4885
- attrInt("gen_ai.usage.output_tokens", outputTokens),
5254
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
5255
+ ...buildModelUsageAttributes(usageMetrics),
4886
5256
  ...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
4887
5257
  ...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
4888
5258
  ...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
@@ -4982,20 +5352,20 @@ function startDoGenerateSpan(operationId, options, modelInfo, parent, ctx) {
4982
5352
  name: operationId,
4983
5353
  parent,
4984
5354
  eventId: ctx.eventId,
5355
+ ...identityFromContext(ctx.context),
4985
5356
  operationId,
4986
5357
  attributes: [
4987
5358
  attrString("operation.name", operationName),
4988
5359
  attrString("resource.name", resourceName),
4989
5360
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
4990
- attrString("ai.model.provider", modelInfo.provider),
5361
+ ...attrsFromModelProvider(modelInfo.provider),
4991
5362
  attrString("ai.model.id", modelInfo.modelId),
4992
5363
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
4993
5364
  attrString("ai.prompt.messages", promptJson),
4994
5365
  attrStringArray("ai.prompt.tools", toolsJson),
4995
5366
  attrString("ai.prompt.toolChoice", toolChoiceJson)
4996
5367
  ],
4997
- attrString("gen_ai.system", modelInfo.provider),
4998
- attrString("gen_ai.request.model", modelInfo.modelId),
5368
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
4999
5369
  ...attrsFromGenAiRequest(options),
5000
5370
  attrProviderOptions(options)
5001
5371
  ]
@@ -5028,8 +5398,12 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5028
5398
  } else {
5029
5399
  responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
5030
5400
  }
5031
- const inputTokens = extractNestedTokens(usage, "inputTokens");
5032
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5401
+ const usageMetrics = extractUsageMetricsFromUsage(
5402
+ usage,
5403
+ modelInfo.provider,
5404
+ providerMetadata
5405
+ );
5406
+ const { inputTokens, outputTokens } = usageMetrics;
5033
5407
  ctx.traceShipper.endSpan(span, {
5034
5408
  attributes: [
5035
5409
  ...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
@@ -5048,9 +5422,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5048
5422
  attrInt("ai.usage.completionTokens", outputTokens),
5049
5423
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5050
5424
  attrString("gen_ai.response.id", responseId),
5051
- attrString("gen_ai.response.model", responseModelId),
5052
- attrInt("gen_ai.usage.input_tokens", inputTokens),
5053
- attrInt("gen_ai.usage.output_tokens", outputTokens)
5425
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
5426
+ ...buildModelUsageAttributes(usageMetrics)
5054
5427
  ]
5055
5428
  });
5056
5429
  }
@@ -5065,20 +5438,20 @@ function startDoStreamSpan(operationId, options, modelInfo, parent, ctx) {
5065
5438
  name: operationId,
5066
5439
  parent,
5067
5440
  eventId: ctx.eventId,
5441
+ ...identityFromContext(ctx.context),
5068
5442
  operationId,
5069
5443
  attributes: [
5070
5444
  attrString("operation.name", operationName),
5071
5445
  attrString("resource.name", resourceName),
5072
5446
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
5073
- attrString("ai.model.provider", modelInfo.provider),
5447
+ ...attrsFromModelProvider(modelInfo.provider),
5074
5448
  attrString("ai.model.id", modelInfo.modelId),
5075
5449
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
5076
5450
  attrString("ai.prompt.messages", promptJson),
5077
5451
  attrStringArray("ai.prompt.tools", toolsJson),
5078
5452
  attrString("ai.prompt.toolChoice", toolChoiceJson)
5079
5453
  ],
5080
- attrString("gen_ai.system", modelInfo.provider),
5081
- attrString("gen_ai.request.model", modelInfo.modelId),
5454
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
5082
5455
  ...attrsFromGenAiRequest(options),
5083
5456
  attrProviderOptions(options)
5084
5457
  ]
@@ -5143,13 +5516,6 @@ function mergeAttachments(...groups) {
5143
5516
  }
5144
5517
  return merged.length ? merged : void 0;
5145
5518
  }
5146
- function extractNestedTokens(usage, key) {
5147
- if (!isRecord(usage)) return void 0;
5148
- const val = usage[key];
5149
- if (typeof val === "number") return val;
5150
- if (isRecord(val) && typeof val["total"] === "number") return val["total"];
5151
- return void 0;
5152
- }
5153
5519
 
5154
5520
  // src/index.ts
5155
5521
  function eventMetadata(options) {
@@ -5325,6 +5691,9 @@ function createRaindropAISDK(opts) {
5325
5691
  const internal = traceShipper.startSpan({
5326
5692
  name: args.name,
5327
5693
  eventId: args.eventId,
5694
+ userId: args.userId,
5695
+ convoId: args.convoId,
5696
+ eventName: args.eventName,
5328
5697
  parent,
5329
5698
  operationId: args.operationId,
5330
5699
  attributes: attrs
@@ -5359,6 +5728,9 @@ function createRaindropAISDK(opts) {
5359
5728
  const internal = traceShipper.startSpan({
5360
5729
  name: args.name,
5361
5730
  eventId: args.eventId,
5731
+ userId: args.userId,
5732
+ convoId: args.convoId,
5733
+ eventName: args.eventName,
5362
5734
  parent,
5363
5735
  operationId: args.operationId,
5364
5736
  attributes: startAttrs,