@raindrop-ai/ai-sdk 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- // ../core/dist/chunk-QTUH3BHZ.js
3
+ // ../core/dist/chunk-QNWZIOOY.js
4
4
  function normalizeFeatureFlags(input) {
5
5
  if (Array.isArray(input)) {
6
6
  return Object.fromEntries(input.map((name) => [name, "true"]));
@@ -826,6 +826,193 @@ var EventShipper = class {
826
826
  }
827
827
  }
828
828
  };
829
+ var MODEL_USAGE_ATTRIBUTES = {
830
+ providerName: "gen_ai.provider.name",
831
+ requestModel: "gen_ai.request.model",
832
+ responseModel: "gen_ai.response.model",
833
+ inputTokens: "gen_ai.usage.input_tokens",
834
+ outputTokens: "gen_ai.usage.output_tokens",
835
+ reasoningTokens: "gen_ai.usage.reasoning_tokens",
836
+ cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
837
+ cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
838
+ nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
839
+ nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
840
+ reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
841
+ cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
842
+ cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
843
+ };
844
+ var MODEL_PROVIDER_NAMES = [
845
+ ["google.vertex", "google-vertex"],
846
+ ["vertex.anthropic", "google-vertex"],
847
+ ["amazon-bedrock", "amazon-bedrock"],
848
+ ["bedrock", "amazon-bedrock"],
849
+ ["anthropic", "anthropic"],
850
+ ["openai", "openai"],
851
+ ["google", "google"],
852
+ ["azure", "azure"],
853
+ ["openrouter", "openrouter"]
854
+ ];
855
+ function canonicalModelProvider(provider) {
856
+ var _a;
857
+ const normalizedProvider = provider.trim().toLowerCase();
858
+ if (normalizedProvider === "gateway") return "vercel";
859
+ const match = MODEL_PROVIDER_NAMES.find(
860
+ ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
861
+ );
862
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
863
+ }
864
+ function tokenCount(value) {
865
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
866
+ }
867
+ function exclusiveTokens({
868
+ explicit,
869
+ total,
870
+ parts,
871
+ semantics
872
+ }) {
873
+ if (explicit !== void 0) return explicit;
874
+ if (total === void 0) return void 0;
875
+ if (semantics === "exclusive") return total;
876
+ const observedParts = parts.filter((part) => part !== void 0 && part > 0);
877
+ if (semantics === void 0 && observedParts.length > 0) return void 0;
878
+ const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
879
+ return exclusive >= 0 ? exclusive : void 0;
880
+ }
881
+ function buildModelUsageAttributes(usage) {
882
+ const inputTokens = tokenCount(usage.inputTokens);
883
+ const outputTokens = tokenCount(usage.outputTokens);
884
+ const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
885
+ const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
886
+ const reasoningTokens = tokenCount(usage.reasoningTokens);
887
+ const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
888
+ const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
889
+ const nonCachedInputTokens = exclusiveTokens({
890
+ explicit: explicitNonCachedInputTokens,
891
+ total: inputTokens,
892
+ parts: [cacheReadInputTokens, cacheWriteInputTokens],
893
+ semantics: usage.inputTokenSemantics
894
+ });
895
+ const nonReasoningOutputTokens = exclusiveTokens({
896
+ explicit: explicitNonReasoningOutputTokens,
897
+ total: outputTokens,
898
+ parts: [reasoningTokens],
899
+ semantics: usage.outputTokenSemantics
900
+ });
901
+ const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
902
+ // backend consumes this complete raindrop.* set as one atomic billing-pool contract.
903
+ attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
904
+ attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
905
+ attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
906
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
907
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
908
+ ] : [];
909
+ return [
910
+ attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
911
+ attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
912
+ attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
913
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
914
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
915
+ ...exclusivePoolAttributes
916
+ ].filter((attribute) => attribute !== void 0);
917
+ }
918
+ var STRING_ALIASES = {
919
+ [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
920
+ };
921
+ var NUMBER_ALIASES = {
922
+ [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
923
+ "gen_ai.usage.prompt_tokens",
924
+ "ai.usage.prompt_tokens",
925
+ "ai.usage.promptTokens",
926
+ "ai.usage.input_tokens",
927
+ "ai.usage.inputTokens"
928
+ ],
929
+ [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
930
+ "gen_ai.usage.completion_tokens",
931
+ "ai.usage.completion_tokens",
932
+ "ai.usage.completionTokens",
933
+ "ai.usage.output_tokens",
934
+ "ai.usage.outputTokens"
935
+ ],
936
+ [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
937
+ "gen_ai.usage.reasoning.output_tokens",
938
+ "ai.usage.reasoningTokens",
939
+ "ai.usage.thoughts_tokens"
940
+ ],
941
+ [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
942
+ "gen_ai.usage.cache_read_tokens",
943
+ "gen_ai.usage.cache_read.input_tokens",
944
+ "ai.usage.cachedInputTokens",
945
+ "ai.usage.cached_tokens",
946
+ "ai.usage.cache_read_tokens",
947
+ "ai.usage.cache_read_input_tokens",
948
+ "ai.usage.cacheReadInputTokens"
949
+ ],
950
+ [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
951
+ "gen_ai.usage.cache_creation_input_tokens",
952
+ "gen_ai.usage.cache_creation.input_tokens",
953
+ "ai.usage.cacheWriteInputTokens",
954
+ "ai.usage.cache_creation_input_tokens",
955
+ "ai.usage.cacheCreationInputTokens"
956
+ ]
957
+ };
958
+ function hasAttribute(attributes, key) {
959
+ return attributes.some((attribute) => attribute.key === key);
960
+ }
961
+ function findStringAttribute(attributes, keys) {
962
+ return attributes.find(
963
+ (attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
964
+ );
965
+ }
966
+ function findNumberAttribute(attributes, keys) {
967
+ return attributes.find((attribute) => {
968
+ if (!keys.includes(attribute.key)) return false;
969
+ if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
970
+ return true;
971
+ }
972
+ const intValue = attribute.value.intValue;
973
+ return integerValue(intValue) !== void 0;
974
+ });
975
+ }
976
+ function integerValue(value) {
977
+ if (typeof value === "number") {
978
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
979
+ }
980
+ if (typeof value !== "string") return void 0;
981
+ const parsed = Number(value);
982
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
983
+ }
984
+ function appendAlias(attributes, target, source) {
985
+ if (!source || hasAttribute(attributes, target)) return attributes;
986
+ return [...attributes, { key: target, value: { ...source.value } }];
987
+ }
988
+ function appendProviderAlias(attributes) {
989
+ if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
990
+ const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
991
+ if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
992
+ const attribute = attrString(
993
+ MODEL_USAGE_ATTRIBUTES.providerName,
994
+ canonicalModelProvider(source.value.stringValue)
995
+ );
996
+ return attribute ? [...attributes, attribute] : attributes;
997
+ }
998
+ function normalizeModelUsageSpan(span) {
999
+ const original = span.attributes;
1000
+ if (!original || original.length === 0) return span;
1001
+ const responseModel = findStringAttribute(original, [
1002
+ MODEL_USAGE_ATTRIBUTES.responseModel,
1003
+ "ai.response.model"
1004
+ ]);
1005
+ if (!responseModel) return span;
1006
+ let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
1007
+ attributes = appendProviderAlias(attributes);
1008
+ for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
1009
+ attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
1010
+ }
1011
+ for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
1012
+ attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
1013
+ }
1014
+ return attributes === original ? span : { ...span, attributes };
1015
+ }
829
1016
  var DEFAULT_SECRET_KEY_NAMES = [
830
1017
  "apikey",
831
1018
  "apisecret",
@@ -1026,6 +1213,10 @@ var TraceShipper = class {
1026
1213
  return null;
1027
1214
  }
1028
1215
  }
1216
+ try {
1217
+ current = normalizeModelUsageSpan(current);
1218
+ } catch (e) {
1219
+ }
1029
1220
  if (!this.disableDefaultRedaction) {
1030
1221
  current = defaultTransformSpan(current);
1031
1222
  }
@@ -1359,7 +1550,7 @@ async function* asyncGeneratorWithCurrent(span, gen) {
1359
1550
  // package.json
1360
1551
  var package_default = {
1361
1552
  name: "@raindrop-ai/ai-sdk",
1362
- version: "0.2.0"};
1553
+ version: "0.2.1"};
1363
1554
 
1364
1555
  // src/internal/version.ts
1365
1556
  var libraryName = package_default.name;
@@ -2056,6 +2247,15 @@ function attrsFromHeaders(headers) {
2056
2247
  if (!isRecord(headers)) return [];
2057
2248
  return Object.entries(headers).filter(([, v]) => typeof v === "string").map(([k, v]) => attrString(`ai.request.headers.${k}`, v));
2058
2249
  }
2250
+ function attrsFromModelProvider(provider) {
2251
+ if (typeof provider !== "string" || provider.length === 0) return [];
2252
+ const providerName = canonicalModelProvider(provider);
2253
+ return [
2254
+ attrString("ai.model.provider", provider),
2255
+ attrString(MODEL_USAGE_ATTRIBUTES.providerName, providerName),
2256
+ attrString("gen_ai.system", provider)
2257
+ ];
2258
+ }
2059
2259
  function attrsFromSettings(args) {
2060
2260
  if (!isRecord(args)) return [];
2061
2261
  const result = [];
@@ -2238,6 +2438,126 @@ function runWithParentToolContext(ctx, fn) {
2238
2438
  return getStorage2().run(ctx, fn);
2239
2439
  }
2240
2440
 
2441
+ // src/internal/usage.ts
2442
+ function firstTokenCount(...values) {
2443
+ for (const value of values) {
2444
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
2445
+ return value;
2446
+ }
2447
+ }
2448
+ return void 0;
2449
+ }
2450
+ function flatUsageSemantics(provider) {
2451
+ const normalizedProvider = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
2452
+ if (normalizedProvider === "anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("anthropic.")) || normalizedProvider === "vertex.anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("vertex.anthropic."))) {
2453
+ return {
2454
+ inputTokenSemantics: "exclusive",
2455
+ outputTokenSemantics: "total"
2456
+ };
2457
+ }
2458
+ if (normalizedProvider === "openai" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("openai.")) || normalizedProvider === "azure" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("azure."))) {
2459
+ return {
2460
+ inputTokenSemantics: "total",
2461
+ outputTokenSemantics: "total"
2462
+ };
2463
+ }
2464
+ if (normalizedProvider === "google" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("google."))) {
2465
+ return {
2466
+ inputTokenSemantics: "total",
2467
+ // Google v5 reports candidate output and thoughts separately.
2468
+ outputTokenSemantics: "exclusive"
2469
+ };
2470
+ }
2471
+ return {};
2472
+ }
2473
+ var CACHE_WRITE_METADATA_KEYS = [
2474
+ ["anthropic", "cacheCreationInputTokens"],
2475
+ ["openai", "cacheWriteTokens"],
2476
+ ["bedrock", "cacheWriteInputTokens"]
2477
+ ];
2478
+ function cacheWriteTokensFromProviderMetadata(providerMetadata) {
2479
+ if (!isRecord(providerMetadata)) return void 0;
2480
+ return firstTokenCount(
2481
+ ...CACHE_WRITE_METADATA_KEYS.flatMap(([namespace, key]) => {
2482
+ const scope = providerMetadata[namespace];
2483
+ if (!isRecord(scope)) return [];
2484
+ const usage = scope["usage"];
2485
+ return [scope[key], isRecord(usage) ? usage[key] : void 0];
2486
+ })
2487
+ );
2488
+ }
2489
+ function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
2490
+ if (!isRecord(usage)) return {};
2491
+ const inputTokenValue = usage["inputTokens"];
2492
+ const outputTokenValue = usage["outputTokens"];
2493
+ const inputTokenDetails = usage["inputTokenDetails"];
2494
+ const outputTokenDetails = usage["outputTokenDetails"];
2495
+ const hasStructuredUsage = isRecord(inputTokenValue) || isRecord(outputTokenValue) || isRecord(inputTokenDetails) || isRecord(outputTokenDetails);
2496
+ const inputTokens = firstTokenCount(
2497
+ isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
2498
+ inputTokenValue,
2499
+ usage["promptTokens"],
2500
+ usage["prompt_tokens"]
2501
+ );
2502
+ const outputTokens = firstTokenCount(
2503
+ isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
2504
+ outputTokenValue,
2505
+ usage["completionTokens"],
2506
+ usage["completion_tokens"]
2507
+ );
2508
+ const reasoningTokens = firstTokenCount(
2509
+ isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
2510
+ isRecord(outputTokenDetails) ? outputTokenDetails["reasoningTokens"] : void 0,
2511
+ usage["reasoningTokens"],
2512
+ usage["completionReasoningTokens"],
2513
+ usage["completion_reasoning_tokens"],
2514
+ usage["reasoning_tokens"],
2515
+ usage["thinkingTokens"],
2516
+ usage["thinking_tokens"]
2517
+ );
2518
+ const cacheReadInputTokens = firstTokenCount(
2519
+ isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
2520
+ isRecord(inputTokenDetails) ? inputTokenDetails["cacheReadTokens"] : void 0,
2521
+ usage["cachedInputTokens"],
2522
+ usage["promptCachedTokens"],
2523
+ usage["prompt_cached_tokens"]
2524
+ );
2525
+ const cacheWriteInputTokens = firstTokenCount(
2526
+ isRecord(inputTokenValue) ? inputTokenValue["cacheWrite"] : void 0,
2527
+ isRecord(inputTokenDetails) ? inputTokenDetails["cacheWriteTokens"] : void 0,
2528
+ usage["cacheWriteInputTokens"],
2529
+ usage["cacheCreationInputTokens"],
2530
+ usage["cache_creation_input_tokens"],
2531
+ cacheWriteTokensFromProviderMetadata(providerMetadata)
2532
+ );
2533
+ const nonCachedInputTokens = firstTokenCount(
2534
+ isRecord(inputTokenValue) ? inputTokenValue["noCache"] : void 0,
2535
+ isRecord(inputTokenDetails) ? inputTokenDetails["noCacheTokens"] : void 0
2536
+ );
2537
+ const nonReasoningOutputTokens = firstTokenCount(
2538
+ isRecord(outputTokenValue) ? outputTokenValue["text"] : void 0,
2539
+ isRecord(outputTokenDetails) ? outputTokenDetails["textTokens"] : void 0
2540
+ );
2541
+ const totalTokens = firstTokenCount(
2542
+ usage["totalTokens"],
2543
+ usage["tokens"],
2544
+ usage["total_tokens"],
2545
+ inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
2546
+ );
2547
+ return {
2548
+ inputTokens,
2549
+ outputTokens,
2550
+ totalTokens,
2551
+ nonCachedInputTokens,
2552
+ nonReasoningOutputTokens,
2553
+ reasoningTokens,
2554
+ cacheReadInputTokens,
2555
+ cachedInputTokens: cacheReadInputTokens,
2556
+ cacheWriteInputTokens,
2557
+ ...hasStructuredUsage ? {} : flatUsageSemantics(provider)
2558
+ };
2559
+ }
2560
+
2241
2561
  // src/internal/raindrop-telemetry-integration.ts
2242
2562
  function hasUnresolvedToolApproval(event) {
2243
2563
  var _a;
@@ -2407,6 +2727,8 @@ var RaindropTelemetryIntegration = class {
2407
2727
  rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
2408
2728
  stepSpan: void 0,
2409
2729
  stepParent: void 0,
2730
+ stepProvider: void 0,
2731
+ stepModelId: void 0,
2410
2732
  toolSpans: /* @__PURE__ */ new Map(),
2411
2733
  embedSpans: /* @__PURE__ */ new Map(),
2412
2734
  parentContextToolCallIds: /* @__PURE__ */ new Set(),
@@ -2460,15 +2782,16 @@ var RaindropTelemetryIntegration = class {
2460
2782
  attrString("operation.name", operationName),
2461
2783
  attrString("resource.name", resourceName),
2462
2784
  attrString("ai.telemetry.functionId", state.functionId),
2463
- attrString("ai.model.provider", event.provider),
2785
+ ...attrsFromModelProvider(event.provider),
2464
2786
  attrString("ai.model.id", event.modelId),
2465
- attrString("gen_ai.system", event.provider),
2466
- attrString("gen_ai.request.model", event.modelId),
2787
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
2467
2788
  ...inputAttrs
2468
2789
  ]
2469
2790
  });
2470
2791
  state.stepSpan = stepSpan;
2471
2792
  state.stepParent = this.spanParentRef(stepSpan);
2793
+ state.stepProvider = event.provider;
2794
+ state.stepModelId = event.modelId;
2472
2795
  };
2473
2796
  this.onToolExecutionStart = (event) => this.toolExecutionStart(event);
2474
2797
  this.onToolExecutionEnd = (event) => this.toolExecutionEnd(event);
@@ -2519,23 +2842,24 @@ var RaindropTelemetryIntegration = class {
2519
2842
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2520
2843
  const state = this.getState(event.callId);
2521
2844
  if (!(state == null ? void 0 : state.stepSpan)) return;
2845
+ const responseModelId = (_b = (_a = event.response) == null ? void 0 : _a.modelId) != null ? _b : state.stepModelId;
2522
2846
  const outputAttrs = [];
2523
2847
  if (state.recordOutputs) {
2524
2848
  outputAttrs.push(
2525
2849
  attrString("ai.response.finishReason", event.finishReason),
2526
- attrString("ai.response.text", capText2((_a = event.text) != null ? _a : void 0)),
2527
- attrString("ai.response.id", (_b = event.response) == null ? void 0 : _b.id),
2528
- attrString("ai.response.model", (_c = event.response) == null ? void 0 : _c.modelId),
2850
+ attrString("ai.response.text", capText2((_c = event.text) != null ? _c : void 0)),
2851
+ attrString("ai.response.id", (_d = event.response) == null ? void 0 : _d.id),
2852
+ attrString("ai.response.model", responseModelId),
2529
2853
  attrString(
2530
2854
  "ai.response.timestamp",
2531
- ((_d = event.response) == null ? void 0 : _d.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_e = event.response) == null ? void 0 : _e.timestamp
2855
+ ((_e = event.response) == null ? void 0 : _e.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_f = event.response) == null ? void 0 : _f.timestamp
2532
2856
  ),
2533
2857
  attrString(
2534
2858
  "ai.response.providerMetadata",
2535
2859
  event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
2536
2860
  )
2537
2861
  );
2538
- if (((_f = event.toolCalls) == null ? void 0 : _f.length) > 0) {
2862
+ if (((_g = event.toolCalls) == null ? void 0 : _g.length) > 0) {
2539
2863
  outputAttrs.push(
2540
2864
  attrString(
2541
2865
  "ai.response.toolCalls",
@@ -2549,7 +2873,7 @@ var RaindropTelemetryIntegration = class {
2549
2873
  )
2550
2874
  );
2551
2875
  }
2552
- if (((_g = event.reasoning) == null ? void 0 : _g.length) > 0) {
2876
+ if (((_h = event.reasoning) == null ? void 0 : _h.length) > 0) {
2553
2877
  const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
2554
2878
  if (reasoningText) {
2555
2879
  outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
@@ -2558,25 +2882,31 @@ var RaindropTelemetryIntegration = class {
2558
2882
  }
2559
2883
  outputAttrs.push(
2560
2884
  attrStringArray("gen_ai.response.finish_reasons", [event.finishReason]),
2561
- attrString("gen_ai.response.id", (_h = event.response) == null ? void 0 : _h.id),
2562
- attrString("gen_ai.response.model", (_i = event.response) == null ? void 0 : _i.modelId)
2885
+ attrString("gen_ai.response.id", (_i = event.response) == null ? void 0 : _i.id),
2886
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId)
2563
2887
  );
2564
2888
  const usage = event.usage;
2565
2889
  if (usage) {
2890
+ const usageMetrics = extractUsageMetricsFromUsage(
2891
+ usage,
2892
+ state.stepProvider,
2893
+ event.providerMetadata
2894
+ );
2566
2895
  outputAttrs.push(
2567
- attrInt("ai.usage.inputTokens", usage.inputTokens),
2568
- attrInt("ai.usage.outputTokens", usage.outputTokens),
2569
- attrInt("ai.usage.totalTokens", usage.totalTokens),
2570
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
2571
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens),
2572
- attrInt("gen_ai.usage.input_tokens", usage.inputTokens),
2573
- attrInt("gen_ai.usage.output_tokens", usage.outputTokens)
2896
+ attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
2897
+ attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
2898
+ attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
2899
+ attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
2900
+ attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens),
2901
+ ...buildModelUsageAttributes(usageMetrics)
2574
2902
  );
2575
2903
  }
2576
2904
  this.emitProviderExecutedToolSpans(event, state);
2577
2905
  this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
2578
2906
  state.stepSpan = void 0;
2579
2907
  state.stepParent = void 0;
2908
+ state.stepProvider = void 0;
2909
+ state.stepModelId = void 0;
2580
2910
  };
2581
2911
  // ── onEmbedStart ────────────────────────────────────────────────────────
2582
2912
  this.onEmbedStart = (event) => {
@@ -2651,6 +2981,8 @@ var RaindropTelemetryIntegration = class {
2651
2981
  const actualError = (_a = event.error) != null ? _a : error;
2652
2982
  if (state.stepSpan) {
2653
2983
  this.traceShipper.endSpan(state.stepSpan, { error: actualError });
2984
+ state.stepProvider = void 0;
2985
+ state.stepModelId = void 0;
2654
2986
  }
2655
2987
  for (const embedSpan of state.embedSpans.values()) {
2656
2988
  this.traceShipper.endSpan(embedSpan, { error: actualError });
@@ -2694,6 +3026,8 @@ var RaindropTelemetryIntegration = class {
2694
3026
  this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
2695
3027
  state.stepSpan = void 0;
2696
3028
  state.stepParent = void 0;
3029
+ state.stepProvider = void 0;
3030
+ state.stepModelId = void 0;
2697
3031
  }
2698
3032
  for (const embedSpan of state.embedSpans.values()) {
2699
3033
  this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
@@ -2993,12 +3327,13 @@ var RaindropTelemetryIntegration = class {
2993
3327
  }
2994
3328
  const usage = (_d = event.totalUsage) != null ? _d : event.usage;
2995
3329
  if (usage) {
3330
+ const usageMetrics = extractUsageMetricsFromUsage(usage);
2996
3331
  outputAttrs.push(
2997
- attrInt("ai.usage.inputTokens", usage.inputTokens),
2998
- attrInt("ai.usage.outputTokens", usage.outputTokens),
2999
- attrInt("ai.usage.totalTokens", usage.totalTokens),
3000
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
3001
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens)
3332
+ attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
3333
+ attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
3334
+ attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
3335
+ attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
3336
+ attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens)
3002
3337
  );
3003
3338
  }
3004
3339
  outputAttrs.push(attrInt("ai.toolCall.count", state.toolCallCount));
@@ -3451,14 +3786,6 @@ function runWithParentSpanContextSync(ctx, fn) {
3451
3786
  function isAsyncIterable(value) {
3452
3787
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
3453
3788
  }
3454
- function firstFiniteNumber(...values) {
3455
- for (const value of values) {
3456
- if (typeof value === "number" && Number.isFinite(value)) {
3457
- return value;
3458
- }
3459
- }
3460
- return void 0;
3461
- }
3462
3789
  function resolveUsageRecord(result) {
3463
3790
  if (!isRecord(result)) return void 0;
3464
3791
  let usage;
@@ -3474,50 +3801,7 @@ function resolveUsageRecord(result) {
3474
3801
  return isRecord(usage) ? usage : void 0;
3475
3802
  }
3476
3803
  function extractUsageMetrics(result) {
3477
- const usage = resolveUsageRecord(result);
3478
- if (!usage) return {};
3479
- const inputTokenValue = usage["inputTokens"];
3480
- const outputTokenValue = usage["outputTokens"];
3481
- const inputTokens = firstFiniteNumber(
3482
- isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
3483
- inputTokenValue,
3484
- usage["promptTokens"],
3485
- usage["prompt_tokens"]
3486
- );
3487
- const outputTokens = firstFiniteNumber(
3488
- isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
3489
- outputTokenValue,
3490
- usage["completionTokens"],
3491
- usage["completion_tokens"]
3492
- );
3493
- const totalTokens = firstFiniteNumber(
3494
- usage["totalTokens"],
3495
- usage["tokens"],
3496
- usage["total_tokens"],
3497
- inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
3498
- );
3499
- const reasoningTokens = firstFiniteNumber(
3500
- isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
3501
- usage["reasoningTokens"],
3502
- usage["completionReasoningTokens"],
3503
- usage["completion_reasoning_tokens"],
3504
- usage["reasoning_tokens"],
3505
- usage["thinkingTokens"],
3506
- usage["thinking_tokens"]
3507
- );
3508
- const cachedInputTokens = firstFiniteNumber(
3509
- isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
3510
- usage["cachedInputTokens"],
3511
- usage["promptCachedTokens"],
3512
- usage["prompt_cached_tokens"]
3513
- );
3514
- return {
3515
- inputTokens,
3516
- outputTokens,
3517
- totalTokens,
3518
- reasoningTokens,
3519
- cachedInputTokens
3520
- };
3804
+ return extractUsageMetricsFromUsage(resolveUsageRecord(result));
3521
3805
  }
3522
3806
  function isObjectOperation(operation) {
3523
3807
  return operation === "generateObject" || operation === "streamObject";
@@ -4908,8 +5192,13 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4908
5192
  ended = true;
4909
5193
  const msToFirstChunk = firstChunkMs !== void 0 ? firstChunkMs - startMs : void 0;
4910
5194
  const msToFinish = finishMs !== void 0 ? finishMs - startMs : void 0;
4911
- const inputTokens = extractNestedTokens(usage, "inputTokens");
4912
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5195
+ const usageMetrics = extractUsageMetricsFromUsage(
5196
+ usage,
5197
+ modelInfo.provider,
5198
+ providerMetadata
5199
+ );
5200
+ const finalResponseModelId = responseModelId != null ? responseModelId : modelInfo.modelId;
5201
+ const { inputTokens, outputTokens } = usageMetrics;
4913
5202
  const avgOutTokensPerSecond = msToFinish && outputTokens !== void 0 && msToFinish > 0 ? 1e3 * outputTokens / msToFinish : void 0;
4914
5203
  ctx.traceShipper.endSpan(span, {
4915
5204
  attributes: [
@@ -4921,7 +5210,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4921
5210
  safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
4922
5211
  ),
4923
5212
  attrString("ai.response.id", responseId),
4924
- attrString("ai.response.model", responseModelId),
5213
+ attrString("ai.response.model", finalResponseModelId),
4925
5214
  attrString("ai.response.timestamp", responseTimestampIso),
4926
5215
  attrString(
4927
5216
  "ai.response.providerMetadata",
@@ -4932,9 +5221,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4932
5221
  attrInt("ai.usage.outputTokens", outputTokens),
4933
5222
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
4934
5223
  attrString("gen_ai.response.id", responseId),
4935
- attrString("gen_ai.response.model", responseModelId),
4936
- attrInt("gen_ai.usage.input_tokens", inputTokens),
4937
- attrInt("gen_ai.usage.output_tokens", outputTokens),
5224
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
5225
+ ...buildModelUsageAttributes(usageMetrics),
4938
5226
  ...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
4939
5227
  ...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
4940
5228
  ...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
@@ -5040,15 +5328,14 @@ function startDoGenerateSpan(operationId, options, modelInfo, parent, ctx) {
5040
5328
  attrString("operation.name", operationName),
5041
5329
  attrString("resource.name", resourceName),
5042
5330
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
5043
- attrString("ai.model.provider", modelInfo.provider),
5331
+ ...attrsFromModelProvider(modelInfo.provider),
5044
5332
  attrString("ai.model.id", modelInfo.modelId),
5045
5333
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
5046
5334
  attrString("ai.prompt.messages", promptJson),
5047
5335
  attrStringArray("ai.prompt.tools", toolsJson),
5048
5336
  attrString("ai.prompt.toolChoice", toolChoiceJson)
5049
5337
  ],
5050
- attrString("gen_ai.system", modelInfo.provider),
5051
- attrString("gen_ai.request.model", modelInfo.modelId),
5338
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
5052
5339
  ...attrsFromGenAiRequest(options),
5053
5340
  attrProviderOptions(options)
5054
5341
  ]
@@ -5081,8 +5368,12 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5081
5368
  } else {
5082
5369
  responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
5083
5370
  }
5084
- const inputTokens = extractNestedTokens(usage, "inputTokens");
5085
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5371
+ const usageMetrics = extractUsageMetricsFromUsage(
5372
+ usage,
5373
+ modelInfo.provider,
5374
+ providerMetadata
5375
+ );
5376
+ const { inputTokens, outputTokens } = usageMetrics;
5086
5377
  ctx.traceShipper.endSpan(span, {
5087
5378
  attributes: [
5088
5379
  ...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
@@ -5101,9 +5392,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5101
5392
  attrInt("ai.usage.completionTokens", outputTokens),
5102
5393
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5103
5394
  attrString("gen_ai.response.id", responseId),
5104
- attrString("gen_ai.response.model", responseModelId),
5105
- attrInt("gen_ai.usage.input_tokens", inputTokens),
5106
- attrInt("gen_ai.usage.output_tokens", outputTokens)
5395
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
5396
+ ...buildModelUsageAttributes(usageMetrics)
5107
5397
  ]
5108
5398
  });
5109
5399
  }
@@ -5124,15 +5414,14 @@ function startDoStreamSpan(operationId, options, modelInfo, parent, ctx) {
5124
5414
  attrString("operation.name", operationName),
5125
5415
  attrString("resource.name", resourceName),
5126
5416
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
5127
- attrString("ai.model.provider", modelInfo.provider),
5417
+ ...attrsFromModelProvider(modelInfo.provider),
5128
5418
  attrString("ai.model.id", modelInfo.modelId),
5129
5419
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
5130
5420
  attrString("ai.prompt.messages", promptJson),
5131
5421
  attrStringArray("ai.prompt.tools", toolsJson),
5132
5422
  attrString("ai.prompt.toolChoice", toolChoiceJson)
5133
5423
  ],
5134
- attrString("gen_ai.system", modelInfo.provider),
5135
- attrString("gen_ai.request.model", modelInfo.modelId),
5424
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
5136
5425
  ...attrsFromGenAiRequest(options),
5137
5426
  attrProviderOptions(options)
5138
5427
  ]
@@ -5197,13 +5486,6 @@ function mergeAttachments(...groups) {
5197
5486
  }
5198
5487
  return merged.length ? merged : void 0;
5199
5488
  }
5200
- function extractNestedTokens(usage, key) {
5201
- if (!isRecord(usage)) return void 0;
5202
- const val = usage[key];
5203
- if (typeof val === "number") return val;
5204
- if (isRecord(val) && typeof val["total"] === "number") return val["total"];
5205
- return void 0;
5206
- }
5207
5489
 
5208
5490
  // src/index.ts
5209
5491
  function eventMetadata(options) {