@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
  import { AsyncLocalStorage } from 'async_hooks';
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
  }
@@ -2060,6 +2251,15 @@ function attrsFromHeaders(headers) {
2060
2251
  if (!isRecord(headers)) return [];
2061
2252
  return Object.entries(headers).filter(([, v]) => typeof v === "string").map(([k, v]) => attrString(`ai.request.headers.${k}`, v));
2062
2253
  }
2254
+ function attrsFromModelProvider(provider) {
2255
+ if (typeof provider !== "string" || provider.length === 0) return [];
2256
+ const providerName = canonicalModelProvider(provider);
2257
+ return [
2258
+ attrString("ai.model.provider", provider),
2259
+ attrString(MODEL_USAGE_ATTRIBUTES.providerName, providerName),
2260
+ attrString("gen_ai.system", provider)
2261
+ ];
2262
+ }
2063
2263
  function attrsFromSettings(args) {
2064
2264
  if (!isRecord(args)) return [];
2065
2265
  const result = [];
@@ -2242,6 +2442,126 @@ function runWithParentToolContext(ctx, fn) {
2242
2442
  return getStorage2().run(ctx, fn);
2243
2443
  }
2244
2444
 
2445
+ // src/internal/usage.ts
2446
+ function firstTokenCount(...values) {
2447
+ for (const value of values) {
2448
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
2449
+ return value;
2450
+ }
2451
+ }
2452
+ return void 0;
2453
+ }
2454
+ function flatUsageSemantics(provider) {
2455
+ const normalizedProvider = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
2456
+ if (normalizedProvider === "anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("anthropic.")) || normalizedProvider === "vertex.anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("vertex.anthropic."))) {
2457
+ return {
2458
+ inputTokenSemantics: "exclusive",
2459
+ outputTokenSemantics: "total"
2460
+ };
2461
+ }
2462
+ if (normalizedProvider === "openai" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("openai.")) || normalizedProvider === "azure" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("azure."))) {
2463
+ return {
2464
+ inputTokenSemantics: "total",
2465
+ outputTokenSemantics: "total"
2466
+ };
2467
+ }
2468
+ if (normalizedProvider === "google" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("google."))) {
2469
+ return {
2470
+ inputTokenSemantics: "total",
2471
+ // Google v5 reports candidate output and thoughts separately.
2472
+ outputTokenSemantics: "exclusive"
2473
+ };
2474
+ }
2475
+ return {};
2476
+ }
2477
+ var CACHE_WRITE_METADATA_KEYS = [
2478
+ ["anthropic", "cacheCreationInputTokens"],
2479
+ ["openai", "cacheWriteTokens"],
2480
+ ["bedrock", "cacheWriteInputTokens"]
2481
+ ];
2482
+ function cacheWriteTokensFromProviderMetadata(providerMetadata) {
2483
+ if (!isRecord(providerMetadata)) return void 0;
2484
+ return firstTokenCount(
2485
+ ...CACHE_WRITE_METADATA_KEYS.flatMap(([namespace, key]) => {
2486
+ const scope = providerMetadata[namespace];
2487
+ if (!isRecord(scope)) return [];
2488
+ const usage = scope["usage"];
2489
+ return [scope[key], isRecord(usage) ? usage[key] : void 0];
2490
+ })
2491
+ );
2492
+ }
2493
+ function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
2494
+ if (!isRecord(usage)) return {};
2495
+ const inputTokenValue = usage["inputTokens"];
2496
+ const outputTokenValue = usage["outputTokens"];
2497
+ const inputTokenDetails = usage["inputTokenDetails"];
2498
+ const outputTokenDetails = usage["outputTokenDetails"];
2499
+ const hasStructuredUsage = isRecord(inputTokenValue) || isRecord(outputTokenValue) || isRecord(inputTokenDetails) || isRecord(outputTokenDetails);
2500
+ const inputTokens = firstTokenCount(
2501
+ isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
2502
+ inputTokenValue,
2503
+ usage["promptTokens"],
2504
+ usage["prompt_tokens"]
2505
+ );
2506
+ const outputTokens = firstTokenCount(
2507
+ isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
2508
+ outputTokenValue,
2509
+ usage["completionTokens"],
2510
+ usage["completion_tokens"]
2511
+ );
2512
+ const reasoningTokens = firstTokenCount(
2513
+ isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
2514
+ isRecord(outputTokenDetails) ? outputTokenDetails["reasoningTokens"] : void 0,
2515
+ usage["reasoningTokens"],
2516
+ usage["completionReasoningTokens"],
2517
+ usage["completion_reasoning_tokens"],
2518
+ usage["reasoning_tokens"],
2519
+ usage["thinkingTokens"],
2520
+ usage["thinking_tokens"]
2521
+ );
2522
+ const cacheReadInputTokens = firstTokenCount(
2523
+ isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
2524
+ isRecord(inputTokenDetails) ? inputTokenDetails["cacheReadTokens"] : void 0,
2525
+ usage["cachedInputTokens"],
2526
+ usage["promptCachedTokens"],
2527
+ usage["prompt_cached_tokens"]
2528
+ );
2529
+ const cacheWriteInputTokens = firstTokenCount(
2530
+ isRecord(inputTokenValue) ? inputTokenValue["cacheWrite"] : void 0,
2531
+ isRecord(inputTokenDetails) ? inputTokenDetails["cacheWriteTokens"] : void 0,
2532
+ usage["cacheWriteInputTokens"],
2533
+ usage["cacheCreationInputTokens"],
2534
+ usage["cache_creation_input_tokens"],
2535
+ cacheWriteTokensFromProviderMetadata(providerMetadata)
2536
+ );
2537
+ const nonCachedInputTokens = firstTokenCount(
2538
+ isRecord(inputTokenValue) ? inputTokenValue["noCache"] : void 0,
2539
+ isRecord(inputTokenDetails) ? inputTokenDetails["noCacheTokens"] : void 0
2540
+ );
2541
+ const nonReasoningOutputTokens = firstTokenCount(
2542
+ isRecord(outputTokenValue) ? outputTokenValue["text"] : void 0,
2543
+ isRecord(outputTokenDetails) ? outputTokenDetails["textTokens"] : void 0
2544
+ );
2545
+ const totalTokens = firstTokenCount(
2546
+ usage["totalTokens"],
2547
+ usage["tokens"],
2548
+ usage["total_tokens"],
2549
+ inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
2550
+ );
2551
+ return {
2552
+ inputTokens,
2553
+ outputTokens,
2554
+ totalTokens,
2555
+ nonCachedInputTokens,
2556
+ nonReasoningOutputTokens,
2557
+ reasoningTokens,
2558
+ cacheReadInputTokens,
2559
+ cachedInputTokens: cacheReadInputTokens,
2560
+ cacheWriteInputTokens,
2561
+ ...hasStructuredUsage ? {} : flatUsageSemantics(provider)
2562
+ };
2563
+ }
2564
+
2245
2565
  // src/internal/raindrop-telemetry-integration.ts
2246
2566
  function hasUnresolvedToolApproval(event) {
2247
2567
  var _a;
@@ -2411,6 +2731,8 @@ var RaindropTelemetryIntegration = class {
2411
2731
  rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
2412
2732
  stepSpan: void 0,
2413
2733
  stepParent: void 0,
2734
+ stepProvider: void 0,
2735
+ stepModelId: void 0,
2414
2736
  toolSpans: /* @__PURE__ */ new Map(),
2415
2737
  embedSpans: /* @__PURE__ */ new Map(),
2416
2738
  parentContextToolCallIds: /* @__PURE__ */ new Set(),
@@ -2464,15 +2786,16 @@ var RaindropTelemetryIntegration = class {
2464
2786
  attrString("operation.name", operationName),
2465
2787
  attrString("resource.name", resourceName),
2466
2788
  attrString("ai.telemetry.functionId", state.functionId),
2467
- attrString("ai.model.provider", event.provider),
2789
+ ...attrsFromModelProvider(event.provider),
2468
2790
  attrString("ai.model.id", event.modelId),
2469
- attrString("gen_ai.system", event.provider),
2470
- attrString("gen_ai.request.model", event.modelId),
2791
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
2471
2792
  ...inputAttrs
2472
2793
  ]
2473
2794
  });
2474
2795
  state.stepSpan = stepSpan;
2475
2796
  state.stepParent = this.spanParentRef(stepSpan);
2797
+ state.stepProvider = event.provider;
2798
+ state.stepModelId = event.modelId;
2476
2799
  };
2477
2800
  this.onToolExecutionStart = (event) => this.toolExecutionStart(event);
2478
2801
  this.onToolExecutionEnd = (event) => this.toolExecutionEnd(event);
@@ -2523,23 +2846,24 @@ var RaindropTelemetryIntegration = class {
2523
2846
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2524
2847
  const state = this.getState(event.callId);
2525
2848
  if (!(state == null ? void 0 : state.stepSpan)) return;
2849
+ const responseModelId = (_b = (_a = event.response) == null ? void 0 : _a.modelId) != null ? _b : state.stepModelId;
2526
2850
  const outputAttrs = [];
2527
2851
  if (state.recordOutputs) {
2528
2852
  outputAttrs.push(
2529
2853
  attrString("ai.response.finishReason", event.finishReason),
2530
- attrString("ai.response.text", capText2((_a = event.text) != null ? _a : void 0)),
2531
- attrString("ai.response.id", (_b = event.response) == null ? void 0 : _b.id),
2532
- attrString("ai.response.model", (_c = event.response) == null ? void 0 : _c.modelId),
2854
+ attrString("ai.response.text", capText2((_c = event.text) != null ? _c : void 0)),
2855
+ attrString("ai.response.id", (_d = event.response) == null ? void 0 : _d.id),
2856
+ attrString("ai.response.model", responseModelId),
2533
2857
  attrString(
2534
2858
  "ai.response.timestamp",
2535
- ((_d = event.response) == null ? void 0 : _d.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_e = event.response) == null ? void 0 : _e.timestamp
2859
+ ((_e = event.response) == null ? void 0 : _e.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_f = event.response) == null ? void 0 : _f.timestamp
2536
2860
  ),
2537
2861
  attrString(
2538
2862
  "ai.response.providerMetadata",
2539
2863
  event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
2540
2864
  )
2541
2865
  );
2542
- if (((_f = event.toolCalls) == null ? void 0 : _f.length) > 0) {
2866
+ if (((_g = event.toolCalls) == null ? void 0 : _g.length) > 0) {
2543
2867
  outputAttrs.push(
2544
2868
  attrString(
2545
2869
  "ai.response.toolCalls",
@@ -2553,7 +2877,7 @@ var RaindropTelemetryIntegration = class {
2553
2877
  )
2554
2878
  );
2555
2879
  }
2556
- if (((_g = event.reasoning) == null ? void 0 : _g.length) > 0) {
2880
+ if (((_h = event.reasoning) == null ? void 0 : _h.length) > 0) {
2557
2881
  const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
2558
2882
  if (reasoningText) {
2559
2883
  outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
@@ -2562,25 +2886,31 @@ var RaindropTelemetryIntegration = class {
2562
2886
  }
2563
2887
  outputAttrs.push(
2564
2888
  attrStringArray("gen_ai.response.finish_reasons", [event.finishReason]),
2565
- attrString("gen_ai.response.id", (_h = event.response) == null ? void 0 : _h.id),
2566
- attrString("gen_ai.response.model", (_i = event.response) == null ? void 0 : _i.modelId)
2889
+ attrString("gen_ai.response.id", (_i = event.response) == null ? void 0 : _i.id),
2890
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId)
2567
2891
  );
2568
2892
  const usage = event.usage;
2569
2893
  if (usage) {
2894
+ const usageMetrics = extractUsageMetricsFromUsage(
2895
+ usage,
2896
+ state.stepProvider,
2897
+ event.providerMetadata
2898
+ );
2570
2899
  outputAttrs.push(
2571
- attrInt("ai.usage.inputTokens", usage.inputTokens),
2572
- attrInt("ai.usage.outputTokens", usage.outputTokens),
2573
- attrInt("ai.usage.totalTokens", usage.totalTokens),
2574
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
2575
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens),
2576
- attrInt("gen_ai.usage.input_tokens", usage.inputTokens),
2577
- attrInt("gen_ai.usage.output_tokens", usage.outputTokens)
2900
+ attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
2901
+ attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
2902
+ attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
2903
+ attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
2904
+ attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens),
2905
+ ...buildModelUsageAttributes(usageMetrics)
2578
2906
  );
2579
2907
  }
2580
2908
  this.emitProviderExecutedToolSpans(event, state);
2581
2909
  this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
2582
2910
  state.stepSpan = void 0;
2583
2911
  state.stepParent = void 0;
2912
+ state.stepProvider = void 0;
2913
+ state.stepModelId = void 0;
2584
2914
  };
2585
2915
  // ── onEmbedStart ────────────────────────────────────────────────────────
2586
2916
  this.onEmbedStart = (event) => {
@@ -2655,6 +2985,8 @@ var RaindropTelemetryIntegration = class {
2655
2985
  const actualError = (_a = event.error) != null ? _a : error;
2656
2986
  if (state.stepSpan) {
2657
2987
  this.traceShipper.endSpan(state.stepSpan, { error: actualError });
2988
+ state.stepProvider = void 0;
2989
+ state.stepModelId = void 0;
2658
2990
  }
2659
2991
  for (const embedSpan of state.embedSpans.values()) {
2660
2992
  this.traceShipper.endSpan(embedSpan, { error: actualError });
@@ -2698,6 +3030,8 @@ var RaindropTelemetryIntegration = class {
2698
3030
  this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
2699
3031
  state.stepSpan = void 0;
2700
3032
  state.stepParent = void 0;
3033
+ state.stepProvider = void 0;
3034
+ state.stepModelId = void 0;
2701
3035
  }
2702
3036
  for (const embedSpan of state.embedSpans.values()) {
2703
3037
  this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
@@ -2997,12 +3331,13 @@ var RaindropTelemetryIntegration = class {
2997
3331
  }
2998
3332
  const usage = (_d = event.totalUsage) != null ? _d : event.usage;
2999
3333
  if (usage) {
3334
+ const usageMetrics = extractUsageMetricsFromUsage(usage);
3000
3335
  outputAttrs.push(
3001
- attrInt("ai.usage.inputTokens", usage.inputTokens),
3002
- attrInt("ai.usage.outputTokens", usage.outputTokens),
3003
- attrInt("ai.usage.totalTokens", usage.totalTokens),
3004
- attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
3005
- attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens)
3336
+ attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
3337
+ attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
3338
+ attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
3339
+ attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
3340
+ attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens)
3006
3341
  );
3007
3342
  }
3008
3343
  outputAttrs.push(attrInt("ai.toolCall.count", state.toolCallCount));
@@ -3442,14 +3777,6 @@ function runWithParentSpanContextSync(ctx, fn) {
3442
3777
  function isAsyncIterable(value) {
3443
3778
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
3444
3779
  }
3445
- function firstFiniteNumber(...values) {
3446
- for (const value of values) {
3447
- if (typeof value === "number" && Number.isFinite(value)) {
3448
- return value;
3449
- }
3450
- }
3451
- return void 0;
3452
- }
3453
3780
  function resolveUsageRecord(result) {
3454
3781
  if (!isRecord(result)) return void 0;
3455
3782
  let usage;
@@ -3465,50 +3792,7 @@ function resolveUsageRecord(result) {
3465
3792
  return isRecord(usage) ? usage : void 0;
3466
3793
  }
3467
3794
  function extractUsageMetrics(result) {
3468
- const usage = resolveUsageRecord(result);
3469
- if (!usage) return {};
3470
- const inputTokenValue = usage["inputTokens"];
3471
- const outputTokenValue = usage["outputTokens"];
3472
- const inputTokens = firstFiniteNumber(
3473
- isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
3474
- inputTokenValue,
3475
- usage["promptTokens"],
3476
- usage["prompt_tokens"]
3477
- );
3478
- const outputTokens = firstFiniteNumber(
3479
- isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
3480
- outputTokenValue,
3481
- usage["completionTokens"],
3482
- usage["completion_tokens"]
3483
- );
3484
- const totalTokens = firstFiniteNumber(
3485
- usage["totalTokens"],
3486
- usage["tokens"],
3487
- usage["total_tokens"],
3488
- inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
3489
- );
3490
- const reasoningTokens = firstFiniteNumber(
3491
- isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
3492
- usage["reasoningTokens"],
3493
- usage["completionReasoningTokens"],
3494
- usage["completion_reasoning_tokens"],
3495
- usage["reasoning_tokens"],
3496
- usage["thinkingTokens"],
3497
- usage["thinking_tokens"]
3498
- );
3499
- const cachedInputTokens = firstFiniteNumber(
3500
- isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
3501
- usage["cachedInputTokens"],
3502
- usage["promptCachedTokens"],
3503
- usage["prompt_cached_tokens"]
3504
- );
3505
- return {
3506
- inputTokens,
3507
- outputTokens,
3508
- totalTokens,
3509
- reasoningTokens,
3510
- cachedInputTokens
3511
- };
3795
+ return extractUsageMetricsFromUsage(resolveUsageRecord(result));
3512
3796
  }
3513
3797
  function isObjectOperation(operation) {
3514
3798
  return operation === "generateObject" || operation === "streamObject";
@@ -4899,8 +5183,13 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4899
5183
  ended = true;
4900
5184
  const msToFirstChunk = firstChunkMs !== void 0 ? firstChunkMs - startMs : void 0;
4901
5185
  const msToFinish = finishMs !== void 0 ? finishMs - startMs : void 0;
4902
- const inputTokens = extractNestedTokens(usage, "inputTokens");
4903
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5186
+ const usageMetrics = extractUsageMetricsFromUsage(
5187
+ usage,
5188
+ modelInfo.provider,
5189
+ providerMetadata
5190
+ );
5191
+ const finalResponseModelId = responseModelId != null ? responseModelId : modelInfo.modelId;
5192
+ const { inputTokens, outputTokens } = usageMetrics;
4904
5193
  const avgOutTokensPerSecond = msToFinish && outputTokens !== void 0 && msToFinish > 0 ? 1e3 * outputTokens / msToFinish : void 0;
4905
5194
  ctx.traceShipper.endSpan(span, {
4906
5195
  attributes: [
@@ -4912,7 +5201,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4912
5201
  safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
4913
5202
  ),
4914
5203
  attrString("ai.response.id", responseId),
4915
- attrString("ai.response.model", responseModelId),
5204
+ attrString("ai.response.model", finalResponseModelId),
4916
5205
  attrString("ai.response.timestamp", responseTimestampIso),
4917
5206
  attrString(
4918
5207
  "ai.response.providerMetadata",
@@ -4923,9 +5212,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4923
5212
  attrInt("ai.usage.outputTokens", outputTokens),
4924
5213
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
4925
5214
  attrString("gen_ai.response.id", responseId),
4926
- attrString("gen_ai.response.model", responseModelId),
4927
- attrInt("gen_ai.usage.input_tokens", inputTokens),
4928
- attrInt("gen_ai.usage.output_tokens", outputTokens),
5215
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
5216
+ ...buildModelUsageAttributes(usageMetrics),
4929
5217
  ...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
4930
5218
  ...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
4931
5219
  ...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
@@ -5031,15 +5319,14 @@ function startDoGenerateSpan(operationId, options, modelInfo, parent, ctx) {
5031
5319
  attrString("operation.name", operationName),
5032
5320
  attrString("resource.name", resourceName),
5033
5321
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
5034
- attrString("ai.model.provider", modelInfo.provider),
5322
+ ...attrsFromModelProvider(modelInfo.provider),
5035
5323
  attrString("ai.model.id", modelInfo.modelId),
5036
5324
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
5037
5325
  attrString("ai.prompt.messages", promptJson),
5038
5326
  attrStringArray("ai.prompt.tools", toolsJson),
5039
5327
  attrString("ai.prompt.toolChoice", toolChoiceJson)
5040
5328
  ],
5041
- attrString("gen_ai.system", modelInfo.provider),
5042
- attrString("gen_ai.request.model", modelInfo.modelId),
5329
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
5043
5330
  ...attrsFromGenAiRequest(options),
5044
5331
  attrProviderOptions(options)
5045
5332
  ]
@@ -5072,8 +5359,12 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5072
5359
  } else {
5073
5360
  responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
5074
5361
  }
5075
- const inputTokens = extractNestedTokens(usage, "inputTokens");
5076
- const outputTokens = extractNestedTokens(usage, "outputTokens");
5362
+ const usageMetrics = extractUsageMetricsFromUsage(
5363
+ usage,
5364
+ modelInfo.provider,
5365
+ providerMetadata
5366
+ );
5367
+ const { inputTokens, outputTokens } = usageMetrics;
5077
5368
  ctx.traceShipper.endSpan(span, {
5078
5369
  attributes: [
5079
5370
  ...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
@@ -5092,9 +5383,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5092
5383
  attrInt("ai.usage.completionTokens", outputTokens),
5093
5384
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5094
5385
  attrString("gen_ai.response.id", responseId),
5095
- attrString("gen_ai.response.model", responseModelId),
5096
- attrInt("gen_ai.usage.input_tokens", inputTokens),
5097
- attrInt("gen_ai.usage.output_tokens", outputTokens)
5386
+ attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
5387
+ ...buildModelUsageAttributes(usageMetrics)
5098
5388
  ]
5099
5389
  });
5100
5390
  }
@@ -5115,15 +5405,14 @@ function startDoStreamSpan(operationId, options, modelInfo, parent, ctx) {
5115
5405
  attrString("operation.name", operationName),
5116
5406
  attrString("resource.name", resourceName),
5117
5407
  attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
5118
- attrString("ai.model.provider", modelInfo.provider),
5408
+ ...attrsFromModelProvider(modelInfo.provider),
5119
5409
  attrString("ai.model.id", modelInfo.modelId),
5120
5410
  ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
5121
5411
  attrString("ai.prompt.messages", promptJson),
5122
5412
  attrStringArray("ai.prompt.tools", toolsJson),
5123
5413
  attrString("ai.prompt.toolChoice", toolChoiceJson)
5124
5414
  ],
5125
- attrString("gen_ai.system", modelInfo.provider),
5126
- attrString("gen_ai.request.model", modelInfo.modelId),
5415
+ attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
5127
5416
  ...attrsFromGenAiRequest(options),
5128
5417
  attrProviderOptions(options)
5129
5418
  ]
@@ -5188,18 +5477,11 @@ function mergeAttachments(...groups) {
5188
5477
  }
5189
5478
  return merged.length ? merged : void 0;
5190
5479
  }
5191
- function extractNestedTokens(usage, key) {
5192
- if (!isRecord(usage)) return void 0;
5193
- const val = usage[key];
5194
- if (typeof val === "number") return val;
5195
- if (isRecord(val) && typeof val["total"] === "number") return val["total"];
5196
- return void 0;
5197
- }
5198
5480
 
5199
5481
  // package.json
5200
5482
  var package_default = {
5201
5483
  name: "@raindrop-ai/ai-sdk",
5202
- version: "0.2.0"};
5484
+ version: "0.2.1"};
5203
5485
 
5204
5486
  // src/internal/version.ts
5205
5487
  var libraryName = package_default.name;