@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.
@@ -4,7 +4,7 @@ var async_hooks = require('async_hooks');
4
4
 
5
5
  // src/index.node.ts
6
6
 
7
- // ../core/dist/chunk-QTUH3BHZ.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"]));
@@ -830,6 +830,193 @@ var EventShipper = class {
830
830
  }
831
831
  }
832
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
+ }
833
1020
  var DEFAULT_SECRET_KEY_NAMES = [
834
1021
  "apikey",
835
1022
  "apisecret",
@@ -1030,6 +1217,10 @@ var TraceShipper = class {
1030
1217
  return null;
1031
1218
  }
1032
1219
  }
1220
+ try {
1221
+ current = normalizeModelUsageSpan(current);
1222
+ } catch (e) {
1223
+ }
1033
1224
  if (!this.disableDefaultRedaction) {
1034
1225
  current = defaultTransformSpan(current);
1035
1226
  }
@@ -1389,7 +1580,7 @@ installTracingSuppressionHook();
1389
1580
  // package.json
1390
1581
  var package_default = {
1391
1582
  name: "@raindrop-ai/ai-sdk",
1392
- version: "0.2.0"};
1583
+ version: "0.2.1"};
1393
1584
 
1394
1585
  // src/internal/version.ts
1395
1586
  var libraryName = package_default.name;
@@ -2086,6 +2277,15 @@ function attrsFromHeaders(headers) {
2086
2277
  if (!isRecord(headers)) return [];
2087
2278
  return Object.entries(headers).filter(([, v]) => typeof v === "string").map(([k, v]) => attrString(`ai.request.headers.${k}`, v));
2088
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
+ }
2089
2289
  function attrsFromSettings(args) {
2090
2290
  if (!isRecord(args)) return [];
2091
2291
  const result = [];
@@ -2268,6 +2468,126 @@ function runWithParentToolContext(ctx, fn) {
2268
2468
  return getStorage2().run(ctx, fn);
2269
2469
  }
2270
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
+
2271
2591
  // src/internal/raindrop-telemetry-integration.ts
2272
2592
  function hasUnresolvedToolApproval(event) {
2273
2593
  var _a;
@@ -2437,6 +2757,8 @@ var RaindropTelemetryIntegration = class {
2437
2757
  rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
2438
2758
  stepSpan: void 0,
2439
2759
  stepParent: void 0,
2760
+ stepProvider: void 0,
2761
+ stepModelId: void 0,
2440
2762
  toolSpans: /* @__PURE__ */ new Map(),
2441
2763
  embedSpans: /* @__PURE__ */ new Map(),
2442
2764
  parentContextToolCallIds: /* @__PURE__ */ new Set(),
@@ -2490,15 +2812,16 @@ var RaindropTelemetryIntegration = class {
2490
2812
  attrString("operation.name", operationName),
2491
2813
  attrString("resource.name", resourceName),
2492
2814
  attrString("ai.telemetry.functionId", state.functionId),
2493
- attrString("ai.model.provider", event.provider),
2815
+ ...attrsFromModelProvider(event.provider),
2494
2816
  attrString("ai.model.id", event.modelId),
2495
- attrString("gen_ai.system", event.provider),
2496
- attrString("gen_ai.request.model", event.modelId),
2817
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
2497
2818
  ...inputAttrs
2498
2819
  ]
2499
2820
  });
2500
2821
  state.stepSpan = stepSpan;
2501
2822
  state.stepParent = this.spanParentRef(stepSpan);
2823
+ state.stepProvider = event.provider;
2824
+ state.stepModelId = event.modelId;
2502
2825
  };
2503
2826
  this.onToolExecutionStart = (event) => this.toolExecutionStart(event);
2504
2827
  this.onToolExecutionEnd = (event) => this.toolExecutionEnd(event);
@@ -2549,23 +2872,24 @@ var RaindropTelemetryIntegration = class {
2549
2872
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2550
2873
  const state = this.getState(event.callId);
2551
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;
2552
2876
  const outputAttrs = [];
2553
2877
  if (state.recordOutputs) {
2554
2878
  outputAttrs.push(
2555
2879
  attrString("ai.response.finishReason", event.finishReason),
2556
- attrString("ai.response.text", capText2((_a = event.text) != null ? _a : void 0)),
2557
- attrString("ai.response.id", (_b = event.response) == null ? void 0 : _b.id),
2558
- 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),
2559
2883
  attrString(
2560
2884
  "ai.response.timestamp",
2561
- ((_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
2562
2886
  ),
2563
2887
  attrString(
2564
2888
  "ai.response.providerMetadata",
2565
2889
  event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
2566
2890
  )
2567
2891
  );
2568
- if (((_f = event.toolCalls) == null ? void 0 : _f.length) > 0) {
2892
+ if (((_g = event.toolCalls) == null ? void 0 : _g.length) > 0) {
2569
2893
  outputAttrs.push(
2570
2894
  attrString(
2571
2895
  "ai.response.toolCalls",
@@ -2579,7 +2903,7 @@ var RaindropTelemetryIntegration = class {
2579
2903
  )
2580
2904
  );
2581
2905
  }
2582
- if (((_g = event.reasoning) == null ? void 0 : _g.length) > 0) {
2906
+ if (((_h = event.reasoning) == null ? void 0 : _h.length) > 0) {
2583
2907
  const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
2584
2908
  if (reasoningText) {
2585
2909
  outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
@@ -2588,25 +2912,31 @@ var RaindropTelemetryIntegration = class {
2588
2912
  }
2589
2913
  outputAttrs.push(
2590
2914
  attrStringArray("gen_ai.response.finish_reasons", [event.finishReason]),
2591
- attrString("gen_ai.response.id", (_h = event.response) == null ? void 0 : _h.id),
2592
- 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)
2593
2917
  );
2594
2918
  const usage = event.usage;
2595
2919
  if (usage) {
2920
+ const usageMetrics = extractUsageMetricsFromUsage(
2921
+ usage,
2922
+ state.stepProvider,
2923
+ event.providerMetadata
2924
+ );
2596
2925
  outputAttrs.push(
2597
- attrInt("ai.usage.inputTokens", usage.inputTokens),
2598
- attrInt("ai.usage.outputTokens", usage.outputTokens),
2599
- attrInt("ai.usage.totalTokens", usage.totalTokens),
2600
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
2601
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens),
2602
- attrInt("gen_ai.usage.input_tokens", usage.inputTokens),
2603
- 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)
2604
2932
  );
2605
2933
  }
2606
2934
  this.emitProviderExecutedToolSpans(event, state);
2607
2935
  this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
2608
2936
  state.stepSpan = void 0;
2609
2937
  state.stepParent = void 0;
2938
+ state.stepProvider = void 0;
2939
+ state.stepModelId = void 0;
2610
2940
  };
2611
2941
  // ── onEmbedStart ────────────────────────────────────────────────────────
2612
2942
  this.onEmbedStart = (event) => {
@@ -2681,6 +3011,8 @@ var RaindropTelemetryIntegration = class {
2681
3011
  const actualError = (_a = event.error) != null ? _a : error;
2682
3012
  if (state.stepSpan) {
2683
3013
  this.traceShipper.endSpan(state.stepSpan, { error: actualError });
3014
+ state.stepProvider = void 0;
3015
+ state.stepModelId = void 0;
2684
3016
  }
2685
3017
  for (const embedSpan of state.embedSpans.values()) {
2686
3018
  this.traceShipper.endSpan(embedSpan, { error: actualError });
@@ -2724,6 +3056,8 @@ var RaindropTelemetryIntegration = class {
2724
3056
  this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
2725
3057
  state.stepSpan = void 0;
2726
3058
  state.stepParent = void 0;
3059
+ state.stepProvider = void 0;
3060
+ state.stepModelId = void 0;
2727
3061
  }
2728
3062
  for (const embedSpan of state.embedSpans.values()) {
2729
3063
  this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
@@ -3023,12 +3357,13 @@ var RaindropTelemetryIntegration = class {
3023
3357
  }
3024
3358
  const usage = (_d = event.totalUsage) != null ? _d : event.usage;
3025
3359
  if (usage) {
3360
+ const usageMetrics = extractUsageMetricsFromUsage(usage);
3026
3361
  outputAttrs.push(
3027
- attrInt("ai.usage.inputTokens", usage.inputTokens),
3028
- attrInt("ai.usage.outputTokens", usage.outputTokens),
3029
- attrInt("ai.usage.totalTokens", usage.totalTokens),
3030
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
3031
- 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)
3032
3367
  );
3033
3368
  }
3034
3369
  outputAttrs.push(attrInt("ai.toolCall.count", state.toolCallCount));
@@ -3481,14 +3816,6 @@ function runWithParentSpanContextSync(ctx, fn) {
3481
3816
  function isAsyncIterable(value) {
3482
3817
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
3483
3818
  }
3484
- function firstFiniteNumber(...values) {
3485
- for (const value of values) {
3486
- if (typeof value === "number" && Number.isFinite(value)) {
3487
- return value;
3488
- }
3489
- }
3490
- return void 0;
3491
- }
3492
3819
  function resolveUsageRecord(result) {
3493
3820
  if (!isRecord(result)) return void 0;
3494
3821
  let usage;
@@ -3504,50 +3831,7 @@ function resolveUsageRecord(result) {
3504
3831
  return isRecord(usage) ? usage : void 0;
3505
3832
  }
3506
3833
  function extractUsageMetrics(result) {
3507
- const usage = resolveUsageRecord(result);
3508
- if (!usage) return {};
3509
- const inputTokenValue = usage["inputTokens"];
3510
- const outputTokenValue = usage["outputTokens"];
3511
- const inputTokens = firstFiniteNumber(
3512
- isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
3513
- inputTokenValue,
3514
- usage["promptTokens"],
3515
- usage["prompt_tokens"]
3516
- );
3517
- const outputTokens = firstFiniteNumber(
3518
- isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
3519
- outputTokenValue,
3520
- usage["completionTokens"],
3521
- usage["completion_tokens"]
3522
- );
3523
- const totalTokens = firstFiniteNumber(
3524
- usage["totalTokens"],
3525
- usage["tokens"],
3526
- usage["total_tokens"],
3527
- inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
3528
- );
3529
- const reasoningTokens = firstFiniteNumber(
3530
- isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
3531
- usage["reasoningTokens"],
3532
- usage["completionReasoningTokens"],
3533
- usage["completion_reasoning_tokens"],
3534
- usage["reasoning_tokens"],
3535
- usage["thinkingTokens"],
3536
- usage["thinking_tokens"]
3537
- );
3538
- const cachedInputTokens = firstFiniteNumber(
3539
- isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
3540
- usage["cachedInputTokens"],
3541
- usage["promptCachedTokens"],
3542
- usage["prompt_cached_tokens"]
3543
- );
3544
- return {
3545
- inputTokens,
3546
- outputTokens,
3547
- totalTokens,
3548
- reasoningTokens,
3549
- cachedInputTokens
3550
- };
3834
+ return extractUsageMetricsFromUsage(resolveUsageRecord(result));
3551
3835
  }
3552
3836
  function isObjectOperation(operation) {
3553
3837
  return operation === "generateObject" || operation === "streamObject";
@@ -4938,8 +5222,13 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4938
5222
  ended = true;
4939
5223
  const msToFirstChunk = firstChunkMs !== void 0 ? firstChunkMs - startMs : void 0;
4940
5224
  const msToFinish = finishMs !== void 0 ? finishMs - startMs : void 0;
4941
- const inputTokens = extractNestedTokens(usage, "inputTokens");
4942
- 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;
4943
5232
  const avgOutTokensPerSecond = msToFinish && outputTokens !== void 0 && msToFinish > 0 ? 1e3 * outputTokens / msToFinish : void 0;
4944
5233
  ctx.traceShipper.endSpan(span, {
4945
5234
  attributes: [
@@ -4951,7 +5240,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4951
5240
  safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
4952
5241
  ),
4953
5242
  attrString("ai.response.id", responseId),
4954
- attrString("ai.response.model", responseModelId),
5243
+ attrString("ai.response.model", finalResponseModelId),
4955
5244
  attrString("ai.response.timestamp", responseTimestampIso),
4956
5245
  attrString(
4957
5246
  "ai.response.providerMetadata",
@@ -4962,9 +5251,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4962
5251
  attrInt("ai.usage.outputTokens", outputTokens),
4963
5252
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
4964
5253
  attrString("gen_ai.response.id", responseId),
4965
- attrString("gen_ai.response.model", responseModelId),
4966
- attrInt("gen_ai.usage.input_tokens", inputTokens),
4967
- attrInt("gen_ai.usage.output_tokens", outputTokens),
5254
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
5255
+ ...buildModelUsageAttributes(usageMetrics),
4968
5256
  ...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
4969
5257
  ...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
4970
5258
  ...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
@@ -5070,15 +5358,14 @@ function startDoGenerateSpan(operationId, options, modelInfo, parent, ctx) {
5070
5358
  attrString("operation.name", operationName),
5071
5359
  attrString("resource.name", resourceName),
5072
5360
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
5073
- attrString("ai.model.provider", modelInfo.provider),
5361
+ ...attrsFromModelProvider(modelInfo.provider),
5074
5362
  attrString("ai.model.id", modelInfo.modelId),
5075
5363
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
5076
5364
  attrString("ai.prompt.messages", promptJson),
5077
5365
  attrStringArray("ai.prompt.tools", toolsJson),
5078
5366
  attrString("ai.prompt.toolChoice", toolChoiceJson)
5079
5367
  ],
5080
- attrString("gen_ai.system", modelInfo.provider),
5081
- attrString("gen_ai.request.model", modelInfo.modelId),
5368
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
5082
5369
  ...attrsFromGenAiRequest(options),
5083
5370
  attrProviderOptions(options)
5084
5371
  ]
@@ -5111,8 +5398,12 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5111
5398
  } else {
5112
5399
  responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
5113
5400
  }
5114
- const inputTokens = extractNestedTokens(usage, "inputTokens");
5115
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5401
+ const usageMetrics = extractUsageMetricsFromUsage(
5402
+ usage,
5403
+ modelInfo.provider,
5404
+ providerMetadata
5405
+ );
5406
+ const { inputTokens, outputTokens } = usageMetrics;
5116
5407
  ctx.traceShipper.endSpan(span, {
5117
5408
  attributes: [
5118
5409
  ...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
@@ -5131,9 +5422,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5131
5422
  attrInt("ai.usage.completionTokens", outputTokens),
5132
5423
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5133
5424
  attrString("gen_ai.response.id", responseId),
5134
- attrString("gen_ai.response.model", responseModelId),
5135
- attrInt("gen_ai.usage.input_tokens", inputTokens),
5136
- attrInt("gen_ai.usage.output_tokens", outputTokens)
5425
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
5426
+ ...buildModelUsageAttributes(usageMetrics)
5137
5427
  ]
5138
5428
  });
5139
5429
  }
@@ -5154,15 +5444,14 @@ function startDoStreamSpan(operationId, options, modelInfo, parent, ctx) {
5154
5444
  attrString("operation.name", operationName),
5155
5445
  attrString("resource.name", resourceName),
5156
5446
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
5157
- attrString("ai.model.provider", modelInfo.provider),
5447
+ ...attrsFromModelProvider(modelInfo.provider),
5158
5448
  attrString("ai.model.id", modelInfo.modelId),
5159
5449
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
5160
5450
  attrString("ai.prompt.messages", promptJson),
5161
5451
  attrStringArray("ai.prompt.tools", toolsJson),
5162
5452
  attrString("ai.prompt.toolChoice", toolChoiceJson)
5163
5453
  ],
5164
- attrString("gen_ai.system", modelInfo.provider),
5165
- attrString("gen_ai.request.model", modelInfo.modelId),
5454
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
5166
5455
  ...attrsFromGenAiRequest(options),
5167
5456
  attrProviderOptions(options)
5168
5457
  ]
@@ -5227,13 +5516,6 @@ function mergeAttachments(...groups) {
5227
5516
  }
5228
5517
  return merged.length ? merged : void 0;
5229
5518
  }
5230
- function extractNestedTokens(usage, key) {
5231
- if (!isRecord(usage)) return void 0;
5232
- const val = usage[key];
5233
- if (typeof val === "number") return val;
5234
- if (isRecord(val) && typeof val["total"] === "number") return val["total"];
5235
- return void 0;
5236
- }
5237
5519
 
5238
5520
  // src/index.ts
5239
5521
  function eventMetadata(options) {