@jeffreycao/copilot-api 1.12.9 → 1.13.0

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,5 +1,5 @@
1
- import { C as setModelMappings, S as resolveMappedModel, T as PATHS, _ as isResponsesApiWebSocketEnabled, a as getExtraPromptForModel, c as getModelResponsesApiCompactThreshold$1, d as getReasoningEffortForModel, f as getSmallModel, g as isResponsesApiWebSearchEnabled, h as isResponsesApiContextManagementEnabled, i as getConfig, l as getProviderConfig, m as isMessagesApiEnabled, n as getAnthropicApiKey, o as getMessageApiWebSearchModel, r as getClaudeTokenMultiplier, s as getModelMappings, u as getRawProviderConfig } from "./config-B71_S_hQ.js";
2
- import { C as prepareMessageProxyHeaders, E as compactMessageSections, F as createPooledWebSocketStream, I as createWebSocketUrl, L as state, M as generateTraceId, N as requestContext, O as compactSystemPromptStarts, P as resolveTraceId$1, R as HTTPError, S as prepareInteractionHeaders, T as compactAutoContinuePromptStarts, _ as getCopilotUsage, b as copilotWebSocketHeaders, d as generateRequestIdFromPayload, f as getRootSessionId, g as sleep, h as parseUserIdMetadata, j as forwardCodexResponses, m as isNullish, p as getUUID, r as setupCodexToken, s as cacheModels, v as copilotBaseUrl, x as prepareForCompact, y as copilotHeaders, z as forwardError } from "./token-fpw8tAQS.js";
1
+ import { C as setModelMappings, S as resolveMappedModel, T as PATHS, _ as isResponsesApiWebSocketEnabled, a as getExtraPromptForModel, c as getModelResponsesApiCompactThreshold$1, d as getReasoningEffortForModel, f as getSmallModel, g as isResponsesApiWebSearchEnabled, h as isResponsesApiContextManagementEnabled, i as getConfig, l as getProviderConfig, m as isMessagesApiEnabled, n as getAnthropicApiKey, o as getMessageApiWebSearchModel, r as getClaudeTokenMultiplier, s as getModelMappings, u as getRawProviderConfig } from "./config-CQxppJtD.js";
2
+ import { B as forwardError, C as prepareInteractionHeaders, D as compactMessageSections, E as compactAutoContinuePromptStarts, F as resolveTraceId$1, I as createPooledWebSocketStream, L as createWebSocketUrl, M as forwardCodexResponses, N as generateTraceId, P as requestContext, R as state, S as prepareForCompact, _ as getCopilotUsage, b as copilotHeaders, d as generateRequestIdFromPayload, f as getRootSessionId, g as sleep, h as parseUserIdMetadata, k as compactSystemPromptStarts, m as isNullish, p as getUUID, r as setupCodexToken, w as prepareMessageProxyHeaders, x as copilotWebSocketHeaders, y as copilotBaseUrl, z as HTTPError } from "./token-CFArcYwb.js";
3
3
  import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, d as shouldEnableResponsesToolSearch, i as isBridgeToolSearchName, l as resolveBridgeToolSearchName, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, t as BRIDGE_TOOL_SEARCH_NAME, u as selectDeferredToolsByNames } from "./tool-search-OX6iPJ9D.js";
4
4
  import consola from "consola";
5
5
  import { createHash } from "node:crypto";
@@ -485,6 +485,7 @@ var SqliteDbStore = class {
485
485
  //#region src/lib/token-usage/store.ts
486
486
  const DB_PATH_ENV = "COPILOT_API_SQLITE_DB_PATH";
487
487
  const DEFAULT_DB_FILENAME = "copilot-api.sqlite";
488
+ const COST_NANOS_PER_UNIT$1 = 1e9;
488
489
  let writeQueue = Promise.resolve();
489
490
  function getDbPath() {
490
491
  return process.env[DB_PATH_ENV] ?? path.join(PATHS.APP_DIR, DEFAULT_DB_FILENAME);
@@ -518,11 +519,19 @@ function initializeTokenUsageDb(db) {
518
519
  output_tokens INTEGER NOT NULL DEFAULT 0,
519
520
  cache_read_input_tokens INTEGER NOT NULL DEFAULT 0,
520
521
  cache_creation_input_tokens INTEGER NOT NULL DEFAULT 0,
521
- total_tokens INTEGER NOT NULL DEFAULT 0
522
+ total_tokens INTEGER NOT NULL DEFAULT 0,
523
+ total_nano_aiu INTEGER,
524
+ cost_currency TEXT,
525
+ total_cost_nanos INTEGER,
526
+ cost_source TEXT
522
527
  )
523
528
  `);
524
529
  ensureColumn(db, "user_id", "TEXT NOT NULL DEFAULT ''");
525
530
  ensureColumn(db, "total_tokens", "INTEGER NOT NULL DEFAULT 0");
531
+ ensureColumn(db, "total_nano_aiu", "INTEGER");
532
+ ensureColumn(db, "cost_currency", "TEXT");
533
+ ensureColumn(db, "total_cost_nanos", "INTEGER");
534
+ ensureColumn(db, "cost_source", "TEXT");
526
535
  db.exec(`
527
536
  CREATE INDEX IF NOT EXISTS idx_token_usage_events_created_at_ms
528
537
  ON token_usage_events(created_at_ms)
@@ -555,7 +564,7 @@ function normalizeOptionalToken(value) {
555
564
  return value === null || value === void 0 ? void 0 : normalizeToken(value);
556
565
  }
557
566
  function hasAnyToken(tokens) {
558
- return normalizeToken(tokens.input_tokens) > 0 || normalizeToken(tokens.output_tokens) > 0 || normalizeToken(tokens.cache_read_input_tokens) > 0 || normalizeToken(tokens.cache_creation_input_tokens) > 0 || normalizeToken(tokens.total_tokens) > 0;
567
+ return normalizeToken(tokens.input_tokens) > 0 || normalizeToken(tokens.output_tokens) > 0 || normalizeToken(tokens.cache_read_input_tokens) > 0 || normalizeToken(tokens.cache_creation_input_tokens) > 0 || normalizeToken(tokens.total_tokens) > 0 || normalizeToken(tokens.total_nano_aiu) > 0;
559
568
  }
560
569
  function resolveTotalTokens(input) {
561
570
  const explicitTotal = normalizeOptionalToken(input.total_tokens);
@@ -578,9 +587,13 @@ async function writeTokenUsageEvent(event) {
578
587
  output_tokens,
579
588
  cache_read_input_tokens,
580
589
  cache_creation_input_tokens,
581
- total_tokens
582
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
583
- `).run(event.created_at_ms, event.created_at_utc, event.trace_id, event.session_id, event.user_id, event.source, event.endpoint, event.provider_name, event.model, event.input_tokens, event.output_tokens, event.cache_read_input_tokens, event.cache_creation_input_tokens, event.total_tokens);
590
+ total_tokens,
591
+ total_nano_aiu,
592
+ cost_currency,
593
+ total_cost_nanos,
594
+ cost_source
595
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
596
+ `).run(event.created_at_ms, event.created_at_utc, event.trace_id, event.session_id, event.user_id, event.source, event.endpoint, event.provider_name, event.model, event.input_tokens, event.output_tokens, event.cache_read_input_tokens, event.cache_creation_input_tokens, event.total_tokens, event.total_nano_aiu, event.cost_currency, event.total_cost_nanos, event.cost_source);
584
597
  }
585
598
  function enqueueTokenUsageWrite(event) {
586
599
  if (!isTokenUsageStorageEnabled()) return;
@@ -651,20 +664,34 @@ function createEmptyTotals() {
651
664
  return {
652
665
  cache_creation_input_tokens: 0,
653
666
  cache_read_input_tokens: 0,
667
+ costs: [],
654
668
  input_tokens: 0,
655
669
  output_tokens: 0,
656
670
  request_count: 0,
671
+ total_nano_aiu: null,
657
672
  total_tokens: 0
658
673
  };
659
674
  }
660
675
  function addTotals(target, next) {
661
676
  target.cache_creation_input_tokens += next.cache_creation_input_tokens;
662
677
  target.cache_read_input_tokens += next.cache_read_input_tokens;
678
+ target.costs = mergeCosts(target.costs, next.costs);
663
679
  target.input_tokens += next.input_tokens;
664
680
  target.output_tokens += next.output_tokens;
665
681
  target.request_count += next.request_count;
682
+ target.total_nano_aiu = addNullableNumbers(target.total_nano_aiu, next.total_nano_aiu);
666
683
  target.total_tokens += next.total_tokens;
667
684
  }
685
+ function addNullableNumbers(current, next) {
686
+ if (current === null) return next;
687
+ if (next === null) return current;
688
+ return current + next;
689
+ }
690
+ function mergeCosts(current, next) {
691
+ const byCurrency = /* @__PURE__ */ new Map();
692
+ for (const cost of [...current, ...next]) byCurrency.set(cost.currency, (byCurrency.get(cost.currency) ?? 0) + cost.total_cost_nanos);
693
+ return [...byCurrency.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([currency, totalCostNanos]) => createCost(currency, totalCostNanos));
694
+ }
668
695
  function createEmptySummary(period) {
669
696
  const range = getPeriodRange(period);
670
697
  return {
@@ -729,19 +756,47 @@ function numberFromRow(row, key) {
729
756
  const value = row?.[key];
730
757
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
731
758
  }
732
- function totalsFromRow(row) {
759
+ function nullableNumberFromRow(row, key) {
760
+ const value = row?.[key];
761
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
762
+ }
763
+ function createCost(currency, totalCostNanos) {
764
+ return {
765
+ amount: totalCostNanos / COST_NANOS_PER_UNIT$1,
766
+ currency,
767
+ total_cost_nanos: totalCostNanos
768
+ };
769
+ }
770
+ function costFromRow(row) {
771
+ const currency = row.cost_currency;
772
+ const totalCostNanos = row.total_cost_nanos;
773
+ if (typeof currency !== "string" || !currency || typeof totalCostNanos !== "number" || !Number.isFinite(totalCostNanos)) return null;
774
+ return createCost(currency, totalCostNanos);
775
+ }
776
+ function eventCostFromRow(row) {
777
+ const cost = costFromRow(row);
778
+ const source = row.cost_source;
779
+ if (!cost || typeof source !== "string" || !source) return null;
780
+ return {
781
+ ...cost,
782
+ source
783
+ };
784
+ }
785
+ function totalsFromRow(row, costs = []) {
733
786
  return {
734
787
  cache_creation_input_tokens: numberFromRow(row, "cache_creation_input_tokens"),
735
788
  cache_read_input_tokens: numberFromRow(row, "cache_read_input_tokens"),
789
+ costs,
736
790
  input_tokens: numberFromRow(row, "input_tokens"),
737
791
  output_tokens: numberFromRow(row, "output_tokens"),
738
792
  request_count: numberFromRow(row, "request_count"),
793
+ total_nano_aiu: nullableNumberFromRow(row, "total_nano_aiu"),
739
794
  total_tokens: numberFromRow(row, "total_tokens")
740
795
  };
741
796
  }
742
- function modelSummaryFromRow(row) {
797
+ function modelSummaryFromRow(row, costs = []) {
743
798
  return {
744
- ...totalsFromRow(row),
799
+ ...totalsFromRow(row, costs),
745
800
  model: typeof row.model === "string" ? row.model : "unknown"
746
801
  };
747
802
  }
@@ -757,6 +812,7 @@ function usageEventFromRow(row) {
757
812
  return {
758
813
  cache_creation_input_tokens: numberFromRow(row, "cache_creation_input_tokens"),
759
814
  cache_read_input_tokens: numberFromRow(row, "cache_read_input_tokens"),
815
+ cost: eventCostFromRow(row),
760
816
  created_at_ms: numberFromRow(row, "created_at_ms"),
761
817
  created_at_utc: stringFromRow(row, "created_at_utc"),
762
818
  endpoint: stringFromRow(row, "endpoint"),
@@ -767,6 +823,7 @@ function usageEventFromRow(row) {
767
823
  provider_name: nullableStringFromRow(row, "provider_name"),
768
824
  session_id: stringFromRow(row, "session_id"),
769
825
  source: stringFromRow(row, "source"),
826
+ total_nano_aiu: nullableNumberFromRow(row, "total_nano_aiu"),
770
827
  total_tokens: numberFromRow(row, "total_tokens"),
771
828
  trace_id: stringFromRow(row, "trace_id"),
772
829
  user_id: stringFromRow(row, "user_id")
@@ -780,6 +837,7 @@ function getTotalsRow(db, range) {
780
837
  COALESCE(SUM(output_tokens), 0) AS output_tokens,
781
838
  COALESCE(SUM(cache_read_input_tokens), 0) AS cache_read_input_tokens,
782
839
  COALESCE(SUM(cache_creation_input_tokens), 0) AS cache_creation_input_tokens,
840
+ SUM(total_nano_aiu) AS total_nano_aiu,
783
841
  COALESCE(SUM(total_tokens), 0) AS total_tokens
784
842
  FROM token_usage_events
785
843
  WHERE created_at_ms >= ? AND created_at_ms < ?
@@ -794,6 +852,7 @@ function getModelRows(db, range) {
794
852
  COALESCE(SUM(output_tokens), 0) AS output_tokens,
795
853
  COALESCE(SUM(cache_read_input_tokens), 0) AS cache_read_input_tokens,
796
854
  COALESCE(SUM(cache_creation_input_tokens), 0) AS cache_creation_input_tokens,
855
+ SUM(total_nano_aiu) AS total_nano_aiu,
797
856
  COALESCE(SUM(total_tokens), 0) AS total_tokens
798
857
  FROM token_usage_events
799
858
  WHERE created_at_ms >= ? AND created_at_ms < ?
@@ -803,8 +862,56 @@ function getModelRows(db, range) {
803
862
  model ASC
804
863
  `).all(range.startMs, range.endMs);
805
864
  }
806
- function createDailyBucket(interval, rows) {
807
- const byModel = rows.map((row) => modelSummaryFromRow(row));
865
+ function getCostRows(db, range) {
866
+ return db.prepare(`
867
+ SELECT
868
+ cost_currency,
869
+ COALESCE(SUM(total_cost_nanos), 0) AS total_cost_nanos
870
+ FROM token_usage_events
871
+ WHERE
872
+ created_at_ms >= ?
873
+ AND created_at_ms < ?
874
+ AND cost_currency IS NOT NULL
875
+ AND total_cost_nanos IS NOT NULL
876
+ GROUP BY cost_currency
877
+ ORDER BY cost_currency ASC
878
+ `).all(range.startMs, range.endMs).flatMap((row) => {
879
+ const cost = costFromRow(row);
880
+ return cost ? [cost] : [];
881
+ });
882
+ }
883
+ function getModelCostMap(db, range) {
884
+ const rows = db.prepare(`
885
+ SELECT
886
+ model,
887
+ cost_currency,
888
+ COALESCE(SUM(total_cost_nanos), 0) AS total_cost_nanos
889
+ FROM token_usage_events
890
+ WHERE
891
+ created_at_ms >= ?
892
+ AND created_at_ms < ?
893
+ AND cost_currency IS NOT NULL
894
+ AND total_cost_nanos IS NOT NULL
895
+ GROUP BY model, cost_currency
896
+ ORDER BY model ASC, cost_currency ASC
897
+ `).all(range.startMs, range.endMs);
898
+ const costMap = /* @__PURE__ */ new Map();
899
+ for (const row of rows) {
900
+ const model = stringFromRow(row, "model") || "unknown";
901
+ const cost = costFromRow(row);
902
+ if (!cost) continue;
903
+ costMap.set(model, [...costMap.get(model) ?? [], cost]);
904
+ }
905
+ return costMap;
906
+ }
907
+ function getModelSummaries(db, range) {
908
+ const costMap = getModelCostMap(db, range);
909
+ return getModelRows(db, range).map((row) => {
910
+ const model = stringFromRow(row, "model") || "unknown";
911
+ return modelSummaryFromRow(row, costMap.get(model) ?? []);
912
+ });
913
+ }
914
+ function createDailyBucket(interval, byModel) {
808
915
  const totals = createEmptyTotals();
809
916
  for (const model of byModel) addTotals(totals, model);
810
917
  return {
@@ -822,10 +929,10 @@ async function getTokenUsageSummary(period) {
822
929
  const db = await getDb();
823
930
  const totalsRow = getTotalsRow(db, range);
824
931
  return {
825
- byModel: getModelRows(db, range).map((row) => modelSummaryFromRow(row)),
932
+ byModel: getModelSummaries(db, range),
826
933
  period,
827
934
  range: rangePayload(range),
828
- totals: totalsFromRow(totalsRow)
935
+ totals: totalsFromRow(totalsRow, getCostRows(db, range))
829
936
  };
830
937
  }
831
938
  async function getTokenUsageDailySummary(period) {
@@ -835,11 +942,11 @@ async function getTokenUsageDailySummary(period) {
835
942
  const db = await getDb();
836
943
  const intervals = createDailyIntervals(range);
837
944
  return {
838
- byModel: getModelRows(db, range).map((row) => modelSummaryFromRow(row)),
839
- days: intervals.map((interval) => createDailyBucket(interval, getModelRows(db, interval))),
945
+ byModel: getModelSummaries(db, range),
946
+ days: intervals.map((interval) => createDailyBucket(interval, getModelSummaries(db, interval))),
840
947
  period,
841
948
  range: rangePayload(range),
842
- totals: totalsFromRow(getTotalsRow(db, range))
949
+ totals: totalsFromRow(getTotalsRow(db, range), getCostRows(db, range))
843
950
  };
844
951
  }
845
952
  async function getTokenUsageEventsPage(input) {
@@ -871,7 +978,11 @@ async function getTokenUsageEventsPage(input) {
871
978
  output_tokens,
872
979
  cache_read_input_tokens,
873
980
  cache_creation_input_tokens,
874
- total_tokens
981
+ total_nano_aiu,
982
+ total_tokens,
983
+ cost_currency,
984
+ total_cost_nanos,
985
+ cost_source
875
986
  FROM token_usage_events
876
987
  WHERE created_at_ms >= ? AND created_at_ms < ?
877
988
  ORDER BY created_at_ms DESC, id DESC
@@ -904,6 +1015,174 @@ async function closeUsageStore() {
904
1015
  }
905
1016
  registerProcessCleanup(closeUsageStore);
906
1017
  //#endregion
1018
+ //#region src/lib/token-usage/pricing.ts
1019
+ const COST_NANOS_PER_UNIT = 1e9;
1020
+ const COST_NANOS_PER_TOKEN_AT_ONE_PER_MILLION = 1e3;
1021
+ const COPILOT_NANO_AIU_TO_COST_NANOS = COST_NANOS_PER_UNIT / 1e11;
1022
+ const BUILTIN_PROVIDER_CURRENCIES = {
1023
+ codex: "USD",
1024
+ dashscope: "CNY",
1025
+ deepseek: "CNY"
1026
+ };
1027
+ const BUILTIN_PROVIDER_PRICING = {
1028
+ codex: {
1029
+ "gpt-5.3-codex": {
1030
+ cachedInput: .175,
1031
+ input: 1.75,
1032
+ output: 14
1033
+ },
1034
+ "gpt-5.4": {
1035
+ cachedInput: .25,
1036
+ input: 2.5,
1037
+ output: 15
1038
+ },
1039
+ "gpt-5.4-mini": {
1040
+ cachedInput: .075,
1041
+ input: .75,
1042
+ output: 4.5
1043
+ },
1044
+ "gpt-5.5": {
1045
+ cachedInput: .5,
1046
+ input: 5,
1047
+ output: 30
1048
+ }
1049
+ },
1050
+ dashscope: {
1051
+ "glm-5.1": { tiers: [{
1052
+ cachedInput: 1.2,
1053
+ cacheCreationInput: 7.5,
1054
+ explicitCachedInput: .6,
1055
+ input: 6,
1056
+ maxInputTokens: 32e3,
1057
+ output: 24
1058
+ }, {
1059
+ cachedInput: 1.6,
1060
+ cacheCreationInput: 10,
1061
+ explicitCachedInput: .8,
1062
+ input: 8,
1063
+ maxInputTokens: 2e5,
1064
+ output: 28
1065
+ }] },
1066
+ "glm-5.2": {
1067
+ cachedInput: 2,
1068
+ cacheCreationInput: 10,
1069
+ explicitCachedInput: .8,
1070
+ input: 8,
1071
+ output: 28
1072
+ },
1073
+ "qwen3.7-max": {
1074
+ cachedInput: 2.4,
1075
+ cacheCreationInput: 15,
1076
+ explicitCachedInput: 1.2,
1077
+ input: 12,
1078
+ output: 36
1079
+ },
1080
+ "qwen3.7-plus": { tiers: [{
1081
+ cachedInput: .4,
1082
+ cacheCreationInput: 2.5,
1083
+ explicitCachedInput: .2,
1084
+ input: 2,
1085
+ maxInputTokens: 256e3,
1086
+ output: 8
1087
+ }, {
1088
+ cachedInput: 1.2,
1089
+ cacheCreationInput: 7.5,
1090
+ explicitCachedInput: .6,
1091
+ input: 6,
1092
+ maxInputTokens: 1e6,
1093
+ output: 24
1094
+ }] }
1095
+ },
1096
+ deepseek: {
1097
+ "deepseek-v4-flash": {
1098
+ cachedInput: .02,
1099
+ input: 1,
1100
+ output: 2
1101
+ },
1102
+ "deepseek-v4-pro": {
1103
+ cachedInput: .025,
1104
+ input: 3,
1105
+ output: 6
1106
+ }
1107
+ }
1108
+ };
1109
+ function resolveTokenUsageCost(input) {
1110
+ if (input.source === "copilot") return resolveCopilotCost(input);
1111
+ const providerName = input.providerName?.trim();
1112
+ if (!providerName) return null;
1113
+ const resolvedPricing = resolveProviderPricing(providerName, input.model, input.pricing);
1114
+ if (!resolvedPricing) return null;
1115
+ const pricing = resolvePricingTier(resolvedPricing.pricing, getInputTokenTotal(input));
1116
+ const currency = resolveProviderCurrency(providerName, input.pricingCurrency);
1117
+ if (!currency) return null;
1118
+ const inputPrice = normalizePrice(pricing.input);
1119
+ const outputPrice = normalizePrice(pricing.output);
1120
+ const cacheReadPrice = resolveCacheReadPrice(pricing, input);
1121
+ const cacheCreationPrice = resolveCacheCreationPrice(pricing);
1122
+ const totalCostNanos = costNanosForTokens(input.input_tokens, inputPrice) + costNanosForTokens(input.output_tokens, outputPrice) + costNanosForTokens(input.cache_read_input_tokens, cacheReadPrice) + costNanosForTokens(input.cache_creation_input_tokens, cacheCreationPrice);
1123
+ if (totalCostNanos <= 0) return null;
1124
+ return {
1125
+ currency,
1126
+ source: resolvedPricing.source,
1127
+ total_cost_nanos: totalCostNanos
1128
+ };
1129
+ }
1130
+ function resolveCopilotCost(input) {
1131
+ const totalNanoAiu = normalizeToken(input.total_nano_aiu);
1132
+ if (totalNanoAiu <= 0) return null;
1133
+ const totalCostNanos = Math.round(totalNanoAiu * COPILOT_NANO_AIU_TO_COST_NANOS);
1134
+ if (totalCostNanos <= 0) return null;
1135
+ return {
1136
+ currency: "USD",
1137
+ source: "copilot_aiu",
1138
+ total_cost_nanos: totalCostNanos
1139
+ };
1140
+ }
1141
+ function resolveProviderPricing(providerName, model, configuredPricing) {
1142
+ if (configuredPricing) return {
1143
+ pricing: configuredPricing,
1144
+ source: "config"
1145
+ };
1146
+ const builtinPricing = BUILTIN_PROVIDER_PRICING[providerName.toLowerCase()]?.[model.toLowerCase()];
1147
+ if (!builtinPricing) return null;
1148
+ return {
1149
+ pricing: builtinPricing,
1150
+ source: "builtin"
1151
+ };
1152
+ }
1153
+ function resolvePricingTier(pricing, inputTokenTotal) {
1154
+ const tiers = pricing.tiers?.filter((tier) => typeof tier === "object" && tier !== null).toSorted((a, b) => normalizeTierMax(a) - normalizeTierMax(b));
1155
+ const selectedTier = tiers?.find((tier) => inputTokenTotal <= normalizeTierMax(tier)) ?? tiers?.at(-1);
1156
+ return {
1157
+ ...pricing,
1158
+ ...selectedTier
1159
+ };
1160
+ }
1161
+ function normalizeTierMax(tier) {
1162
+ const maxInputTokens = tier.maxInputTokens;
1163
+ return typeof maxInputTokens === "number" && Number.isFinite(maxInputTokens) && maxInputTokens > 0 ? maxInputTokens : Number.POSITIVE_INFINITY;
1164
+ }
1165
+ function getInputTokenTotal(input) {
1166
+ return normalizeToken(input.input_tokens) + normalizeToken(input.cache_read_input_tokens) + normalizeToken(input.cache_creation_input_tokens);
1167
+ }
1168
+ function normalizePrice(value) {
1169
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
1170
+ }
1171
+ function resolveProviderCurrency(providerName, configuredCurrency) {
1172
+ return configuredCurrency?.trim().toUpperCase() || BUILTIN_PROVIDER_CURRENCIES[providerName.toLowerCase()] || null;
1173
+ }
1174
+ function resolveCacheCreationPrice(pricing) {
1175
+ return normalizePrice(pricing.cacheCreationInput);
1176
+ }
1177
+ function resolveCacheReadPrice(pricing, input) {
1178
+ if (input.cache_creation_input_tokens !== void 0 && input.cache_creation_input_tokens !== null) return normalizePrice(pricing.explicitCachedInput);
1179
+ return normalizePrice(pricing.cachedInput);
1180
+ }
1181
+ function costNanosForTokens(tokens, pricePerMillionTokens) {
1182
+ if (pricePerMillionTokens === null) return 0;
1183
+ return Math.round(normalizeToken(tokens) * pricePerMillionTokens * COST_NANOS_PER_TOKEN_AT_ONE_PER_MILLION);
1184
+ }
1185
+ //#endregion
907
1186
  //#region src/lib/token-usage/index.ts
908
1187
  const tokenUsageEventBus = new EventBus();
909
1188
  function resolveTraceId(traceId) {
@@ -919,9 +1198,12 @@ function resolveUserId(input) {
919
1198
  function toPersistedEvent(input) {
920
1199
  if (!hasAnyToken(input)) return null;
921
1200
  const now = /* @__PURE__ */ new Date();
1201
+ const cost = resolveTokenUsageCost(input);
922
1202
  return {
923
1203
  cache_creation_input_tokens: normalizeToken(input.cache_creation_input_tokens),
924
1204
  cache_read_input_tokens: normalizeToken(input.cache_read_input_tokens),
1205
+ cost_currency: cost?.currency ?? null,
1206
+ cost_source: cost?.source ?? null,
925
1207
  created_at_ms: now.getTime(),
926
1208
  created_at_utc: now.toISOString(),
927
1209
  endpoint: input.endpoint,
@@ -931,6 +1213,8 @@ function toPersistedEvent(input) {
931
1213
  provider_name: input.providerName?.trim() || null,
932
1214
  session_id: resolveTokenUsageSessionId(input.sessionId, input.fallbackSessionId),
933
1215
  source: input.source,
1216
+ total_nano_aiu: input.total_nano_aiu === void 0 || input.total_nano_aiu === null ? null : normalizeToken(input.total_nano_aiu),
1217
+ total_cost_nanos: cost?.total_cost_nanos ?? null,
934
1218
  total_tokens: resolveTotalTokens(input),
935
1219
  trace_id: resolveTraceId(input.traceId),
936
1220
  user_id: resolveUserId(input)
@@ -963,12 +1247,21 @@ function createProviderTokenUsageRecorder(options) {
963
1247
  });
964
1248
  }
965
1249
  function normalizeOpenAIUsage(usage) {
966
- const cachedTokens = normalizeToken(usage?.prompt_tokens_details?.cached_tokens);
967
- const cacheCreationTokens = normalizeToken(usage?.prompt_tokens_details?.cache_creation_input_tokens);
1250
+ if (usage && (Object.hasOwn(usage, "prompt_cache_hit_tokens") || Object.hasOwn(usage, "prompt_cache_miss_tokens"))) return {
1251
+ cache_read_input_tokens: normalizeToken(usage.prompt_cache_hit_tokens),
1252
+ input_tokens: normalizeToken(usage.prompt_cache_miss_tokens),
1253
+ output_tokens: normalizeToken(usage.completion_tokens),
1254
+ total_tokens: normalizeOptionalToken(usage.total_tokens)
1255
+ };
1256
+ const promptDetails = usage?.prompt_tokens_details;
1257
+ const hasCacheCreationTokens = Boolean(promptDetails && Object.hasOwn(promptDetails, "cache_creation_input_tokens"));
1258
+ const hasCachedTokens = Boolean(promptDetails && Object.hasOwn(promptDetails, "cached_tokens"));
1259
+ const cachedTokens = normalizeToken(promptDetails?.cached_tokens);
1260
+ const cacheCreationTokens = normalizeToken(promptDetails?.cache_creation_input_tokens);
968
1261
  const promptTokens = normalizeToken(usage?.prompt_tokens);
969
1262
  return {
970
- cache_creation_input_tokens: cacheCreationTokens,
971
- cache_read_input_tokens: cachedTokens,
1263
+ ...hasCacheCreationTokens && { cache_creation_input_tokens: cacheCreationTokens },
1264
+ ...hasCachedTokens && { cache_read_input_tokens: cachedTokens },
972
1265
  input_tokens: Math.max(0, promptTokens - cachedTokens - cacheCreationTokens),
973
1266
  output_tokens: normalizeToken(usage?.completion_tokens),
974
1267
  total_tokens: normalizeOptionalToken(usage?.total_tokens)
@@ -1128,7 +1421,7 @@ async function handleProviderChatCompletionsForProvider(c, options) {
1128
1421
  });
1129
1422
  throw new HTTPError(`Failed to create ${provider} chat completions`, upstreamResponse);
1130
1423
  }
1131
- const recordUsage = createProviderChatCompletionsUsageRecorder(payload, provider);
1424
+ const recordUsage = createProviderChatCompletionsUsageRecorder(payload, provider, modelConfig, providerConfig.pricingCurrency);
1132
1425
  const contentType = upstreamResponse.headers.get("content-type") ?? "";
1133
1426
  if (Boolean(payload.stream) && contentType.includes("text/event-stream")) return streamProviderChatCompletions(c, upstreamResponse, {
1134
1427
  provider,
@@ -1154,9 +1447,11 @@ const applyProviderStreamOptions = (payload) => {
1154
1447
  include_usage: true
1155
1448
  };
1156
1449
  };
1157
- const createProviderChatCompletionsUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
1450
+ const createProviderChatCompletionsUsageRecorder = (payload, provider, modelConfig, pricingCurrency) => createProviderTokenUsageRecorder({
1158
1451
  endpoint: "chat_completions",
1159
1452
  model: payload.model,
1453
+ pricing: modelConfig?.pricing,
1454
+ pricingCurrency,
1160
1455
  providerName: provider
1161
1456
  });
1162
1457
  const streamProviderChatCompletions = (c, upstreamResponse, options) => {
@@ -1336,7 +1631,10 @@ async function handleCompletion$1(c) {
1336
1631
  });
1337
1632
  if (isNonStreaming$1(response)) {
1338
1633
  debugJson(logger$7, "Non-streaming response:", response);
1339
- recordUsage(normalizeOpenAIUsage(response.usage));
1634
+ recordUsage({
1635
+ ...normalizeOpenAIUsage(response.usage),
1636
+ total_nano_aiu: normalizeOptionalToken(response.copilot_usage?.total_nano_aiu)
1637
+ });
1340
1638
  return c.json(response);
1341
1639
  }
1342
1640
  logger$7.debug("Streaming response");
@@ -1345,7 +1643,10 @@ async function handleCompletion$1(c) {
1345
1643
  for await (const chunk of response) {
1346
1644
  debugJson(logger$7, "Streaming chunk:", chunk);
1347
1645
  const parsedChunk = parseChatCompletionChunk(chunk);
1348
- if (parsedChunk?.usage) usage = normalizeOpenAIUsage(parsedChunk.usage);
1646
+ if (parsedChunk?.usage || parsedChunk?.copilot_usage) usage = {
1647
+ ...normalizeOpenAIUsage(parsedChunk.usage),
1648
+ total_nano_aiu: normalizeOptionalToken(parsedChunk.copilot_usage?.total_nano_aiu)
1649
+ };
1349
1650
  await stream.writeSSE(chunk);
1350
1651
  }
1351
1652
  recordUsage(usage);
@@ -4512,39 +4813,47 @@ const createWebSearchResponsesStreamCollection = () => ({
4512
4813
  textPartsByKey: /* @__PURE__ */ new Map()
4513
4814
  });
4514
4815
  const collectWebSearchResponsesStreamEvent = (event, state) => {
4515
- if (event.type === "response.created") {
4516
- state.createdResponse = getResponsesResult(event.response);
4517
- return;
4518
- }
4519
- if (isResponsesTerminalEvent(event)) {
4520
- state.terminalResponse = event.response;
4521
- return;
4522
- }
4523
- if (event.type === "response.output_item.added" || event.type === "response.output_item.done") {
4524
- const outputIndex = getNumber(event.output_index);
4525
- const item = getRecord(event.item);
4526
- if (outputIndex !== void 0 && item) state.outputItemsByIndex.set(outputIndex, item);
4527
- return;
4528
- }
4529
- if (event.type === "response.output_text.delta") {
4530
- const part = getOrCreateOutputTextPart(event, state);
4531
- const delta = getString(event.delta);
4532
- if (part && delta) part.text += delta;
4533
- return;
4534
- }
4535
- if (event.type === "response.output_text.done") {
4536
- const part = getOrCreateOutputTextPart(event, state);
4537
- const text = getString(event.text);
4538
- if (part && text !== void 0) part.text = text;
4539
- return;
4540
- }
4541
- if (event.type === "response.output_text.annotation.added") {
4542
- const part = getOrCreateOutputTextPart(event, state);
4543
- const annotation = event.annotation;
4544
- if (part && annotation !== void 0) part.annotations.push(annotation);
4545
- return;
4816
+ switch (event.type) {
4817
+ case "response.created":
4818
+ state.createdResponse = getResponsesResult(event.response);
4819
+ break;
4820
+ case "response.completed":
4821
+ case "response.failed":
4822
+ case "response.incomplete":
4823
+ if (isResponsesTerminalEvent(event)) {
4824
+ event.response.copilot_usage ??= event.copilot_usage;
4825
+ state.terminalResponse = event.response;
4826
+ }
4827
+ break;
4828
+ case "response.output_item.added":
4829
+ case "response.output_item.done": {
4830
+ const outputIndex = getNumber(event.output_index);
4831
+ const item = getRecord(event.item);
4832
+ if (outputIndex !== void 0 && item) state.outputItemsByIndex.set(outputIndex, item);
4833
+ break;
4834
+ }
4835
+ case "response.output_text.delta": {
4836
+ const part = getOrCreateOutputTextPart(event, state);
4837
+ const delta = getString(event.delta);
4838
+ if (part && delta) part.text += delta;
4839
+ break;
4840
+ }
4841
+ case "response.output_text.done": {
4842
+ const part = getOrCreateOutputTextPart(event, state);
4843
+ const text = getString(event.text);
4844
+ if (part && text !== void 0) part.text = text;
4845
+ break;
4846
+ }
4847
+ case "response.output_text.annotation.added": {
4848
+ const part = getOrCreateOutputTextPart(event, state);
4849
+ const annotation = event.annotation;
4850
+ if (part && annotation !== void 0) part.annotations.push(annotation);
4851
+ break;
4852
+ }
4853
+ case "response.content_part.done":
4854
+ collectDoneContentPart(event, state);
4855
+ break;
4546
4856
  }
4547
- if (event.type === "response.content_part.done") collectDoneContentPart(event, state);
4548
4857
  };
4549
4858
  const buildWebSearchResponsesStreamResult = (state) => {
4550
4859
  const response = state.terminalResponse ?? state.createdResponse;
@@ -4692,7 +5001,10 @@ const handleWebSearchViaResponses = async (c, payload, options) => {
4692
5001
  }) : upstreamResult;
4693
5002
  const { extract, response } = reconstructWebSearchResponse(payload, result, { requestId: options.requestId });
4694
5003
  debugJson(logger, `Web search via responses: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s)`, result);
4695
- createUsageRecorder(payload, options.sessionId, webSearchModel)(normalizeResponsesUsage(result.usage));
5004
+ createUsageRecorder(payload, options.sessionId, webSearchModel)({
5005
+ ...normalizeResponsesUsage(result.usage),
5006
+ total_nano_aiu: normalizeOptionalToken(result.copilot_usage?.total_nano_aiu)
5007
+ });
4696
5008
  if (!wantsStream) return c.json(response);
4697
5009
  return streamSSE(c, async (stream) => {
4698
5010
  for (const event of buildSyntheticStreamEvents(response)) await stream.writeSSE({
@@ -4891,6 +5203,7 @@ async function handleProviderMessagesForProvider(c, options) {
4891
5203
  if (providerConfig.type === "openai-responses") {
4892
5204
  if (hasWebSearchServerTool(payload)) {
4893
5205
  if (isWebSearchOnlyRequest(payload)) return await handleOpenAIResponsesProviderWebSearchMessages(c, {
5206
+ modelConfig,
4894
5207
  payload,
4895
5208
  provider,
4896
5209
  providerConfig
@@ -4926,13 +5239,17 @@ async function handleProviderMessagesForProvider(c, options) {
4926
5239
  const contentType = upstreamResponse.headers.get("content-type") ?? "";
4927
5240
  if (Boolean(payload.stream) && contentType.includes("text/event-stream")) return streamProviderMessages({
4928
5241
  c,
5242
+ modelConfig,
4929
5243
  payload,
5244
+ pricingCurrency: providerConfig.pricingCurrency,
4930
5245
  provider,
4931
5246
  upstreamResponse
4932
5247
  });
4933
5248
  return respondProviderMessagesJson(c, {
4934
5249
  body: await upstreamResponse.json(),
5250
+ modelConfig,
4935
5251
  payload,
5252
+ pricingCurrency: providerConfig.pricingCurrency,
4936
5253
  provider
4937
5254
  });
4938
5255
  } catch (error) {
@@ -4944,7 +5261,7 @@ async function handleProviderMessagesForProvider(c, options) {
4944
5261
  }
4945
5262
  }
4946
5263
  const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
4947
- const { payload, provider, providerConfig } = options;
5264
+ const { modelConfig, payload, provider, providerConfig } = options;
4948
5265
  const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
4949
5266
  const responsesPayload = prepareWebSearchResponsesPayload(payload);
4950
5267
  responsesPayload.stream = true;
@@ -4963,12 +5280,16 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
4963
5280
  upstreamResponse,
4964
5281
  logger: logger$5
4965
5282
  }),
5283
+ modelConfig,
4966
5284
  payload,
5285
+ pricingCurrency: providerConfig.pricingCurrency,
4967
5286
  provider
4968
5287
  });
4969
5288
  return respondWebSearchProviderMessagesJson(c, {
4970
5289
  body: upstreamResponse,
5290
+ modelConfig,
4971
5291
  payload,
5292
+ pricingCurrency: providerConfig.pricingCurrency,
4972
5293
  provider
4973
5294
  });
4974
5295
  }
@@ -4987,17 +5308,21 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
4987
5308
  upstreamResponse: events(upstreamResponse),
4988
5309
  logger: logger$5
4989
5310
  }),
5311
+ modelConfig,
4990
5312
  payload,
5313
+ pricingCurrency: providerConfig.pricingCurrency,
4991
5314
  provider
4992
5315
  });
4993
5316
  return respondWebSearchProviderMessagesJson(c, {
4994
5317
  body: await upstreamResponse.json(),
5318
+ modelConfig,
4995
5319
  payload,
5320
+ pricingCurrency: providerConfig.pricingCurrency,
4996
5321
  provider
4997
5322
  });
4998
5323
  };
4999
5324
  const handleOpenAIResponsesProviderMessages = async (c, options) => {
5000
- const { payload, provider, providerConfig } = options;
5325
+ const { modelConfig, payload, provider, providerConfig } = options;
5001
5326
  const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
5002
5327
  const responsesPayload = translateAnthropicMessagesToResponsesPayload(payload);
5003
5328
  applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
@@ -5010,14 +5335,18 @@ const handleOpenAIResponsesProviderMessages = async (c, options) => {
5010
5335
  const upstreamResponse = await forwardCodexResponses(responsesPayload, c.req.raw.headers, providerConfig.baseUrl);
5011
5336
  if (responsesPayload.stream && isResponsesStream$1(upstreamResponse)) return streamResponsesProviderMessages({
5012
5337
  c,
5338
+ modelConfig,
5013
5339
  payload,
5340
+ pricingCurrency: providerConfig.pricingCurrency,
5014
5341
  provider,
5015
5342
  providerConfig,
5016
5343
  upstreamResponse
5017
5344
  });
5018
5345
  return respondResponsesProviderMessagesJson(c, {
5019
5346
  body: upstreamResponse,
5347
+ modelConfig,
5020
5348
  payload,
5349
+ pricingCurrency: providerConfig.pricingCurrency,
5021
5350
  provider,
5022
5351
  providerConfig
5023
5352
  });
@@ -5029,14 +5358,18 @@ const handleOpenAIResponsesProviderMessages = async (c, options) => {
5029
5358
  }
5030
5359
  if (responsesPayload.stream) return streamResponsesProviderMessages({
5031
5360
  c,
5361
+ modelConfig,
5032
5362
  payload,
5363
+ pricingCurrency: providerConfig.pricingCurrency,
5033
5364
  provider,
5034
5365
  providerConfig,
5035
5366
  upstreamResponse: events(upstreamResponse)
5036
5367
  });
5037
5368
  return respondResponsesProviderMessagesJson(c, {
5038
5369
  body: await upstreamResponse.json(),
5370
+ modelConfig,
5039
5371
  payload,
5372
+ pricingCurrency: providerConfig.pricingCurrency,
5040
5373
  provider,
5041
5374
  providerConfig
5042
5375
  });
@@ -5083,13 +5416,17 @@ const handleOpenAICompatibleProviderMessages = async (c, options) => {
5083
5416
  const contentType = upstreamResponse.headers.get("content-type") ?? "";
5084
5417
  if (Boolean(openAIPayload.stream) && contentType.includes("text/event-stream")) return streamOpenAICompatibleProviderMessages({
5085
5418
  c,
5419
+ modelConfig,
5086
5420
  payload,
5421
+ pricingCurrency: providerConfig.pricingCurrency,
5087
5422
  provider,
5088
5423
  upstreamResponse
5089
5424
  });
5090
5425
  return respondOpenAICompatibleProviderMessagesJson(c, {
5091
5426
  body: await upstreamResponse.json(),
5427
+ modelConfig,
5092
5428
  payload,
5429
+ pricingCurrency: providerConfig.pricingCurrency,
5093
5430
  provider
5094
5431
  });
5095
5432
  };
@@ -5158,9 +5495,9 @@ const applyContextCacheControl = (message) => {
5158
5495
  const setContextCacheControl = (part) => {
5159
5496
  part.cache_control = { ...OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL };
5160
5497
  };
5161
- const streamProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
5498
+ const streamProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse }) => {
5162
5499
  logger$5.debug("provider.messages.streaming");
5163
- const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
5500
+ const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
5164
5501
  return streamSSE(c, async (stream) => {
5165
5502
  let usage = {};
5166
5503
  for await (const chunk of events(upstreamResponse)) {
@@ -5189,9 +5526,9 @@ const streamProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
5189
5526
  recordUsage(usage);
5190
5527
  });
5191
5528
  };
5192
- const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
5529
+ const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse }) => {
5193
5530
  logger$5.debug("provider.messages.openai_compatible.streaming");
5194
- const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
5531
+ const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
5195
5532
  return streamSSE(c, async (stream) => {
5196
5533
  let usage = {};
5197
5534
  const streamState = {
@@ -5238,9 +5575,9 @@ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstream
5238
5575
  recordUsage(usage);
5239
5576
  });
5240
5577
  };
5241
- const streamResponsesProviderMessages = ({ c, payload, provider, providerConfig, upstreamResponse }) => {
5578
+ const streamResponsesProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, providerConfig, upstreamResponse }) => {
5242
5579
  logger$5.debug("provider.messages.responses.streaming", { provider });
5243
- const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
5580
+ const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
5244
5581
  return streamSSE(c, async (stream) => {
5245
5582
  let usage = {};
5246
5583
  const streamState = createResponsesStreamState({ toolSearchName: resolveBridgeToolSearchName(payload.tools) });
@@ -5333,29 +5670,29 @@ const parseProviderStreamEvent = (data) => {
5333
5670
  }
5334
5671
  };
5335
5672
  const respondProviderMessagesJson = (c, options) => {
5336
- const { body, payload, provider } = options;
5337
- createProviderMessagesUsageRecorder(payload, provider)(normalizeAnthropicUsage(body.usage));
5673
+ const { body, modelConfig, payload, pricingCurrency, provider } = options;
5674
+ createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeAnthropicUsage(body.usage));
5338
5675
  debugJson(logger$5, "provider.messages.no_stream result:", body);
5339
5676
  return c.json(body);
5340
5677
  };
5341
5678
  const respondOpenAICompatibleProviderMessagesJson = (c, options) => {
5342
- const { body, payload, provider } = options;
5343
- createProviderMessagesUsageRecorder(payload, provider)(normalizeOpenAIUsage(body.usage));
5679
+ const { body, modelConfig, payload, pricingCurrency, provider } = options;
5680
+ createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeOpenAIUsage(body.usage));
5344
5681
  const anthropicResponse = translateToAnthropic(body);
5345
5682
  debugJson(logger$5, "provider.messages.openai_compatible.no_stream result:", anthropicResponse);
5346
5683
  return c.json(anthropicResponse);
5347
5684
  };
5348
5685
  const respondResponsesProviderMessagesJson = (c, options) => {
5349
- const { body, payload, provider, providerConfig } = options;
5350
- createProviderMessagesUsageRecorder(payload, provider)(normalizeResponsesUsage(body.usage));
5686
+ const { body, modelConfig, payload, pricingCurrency, provider, providerConfig } = options;
5687
+ createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeResponsesUsage(body.usage));
5351
5688
  const anthropicResponse = translateResponsesResultToAnthropic(body, { toolSearchName: resolveBridgeToolSearchName(payload.tools) });
5352
5689
  debugJson(logger$5, "provider.messages.responses.no_stream result:", anthropicResponse);
5353
5690
  if (providerConfig.name === "codex") logger$5.debug("provider.messages.codex.no_stream.result");
5354
5691
  return c.json(anthropicResponse);
5355
5692
  };
5356
5693
  const respondWebSearchProviderMessagesJson = (c, options) => {
5357
- const { body, payload, provider } = options;
5358
- createProviderMessagesUsageRecorder(payload, provider)(normalizeResponsesUsage(body.usage));
5694
+ const { body, modelConfig, payload, pricingCurrency, provider } = options;
5695
+ createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeResponsesUsage(body.usage));
5359
5696
  const { extract, response } = reconstructWebSearchResponse(payload, body, { requestId: body.id || `${provider}:${payload.model}` });
5360
5697
  logger$5.debug(`provider.messages.responses.web_search: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s)`);
5361
5698
  if (!payload.stream) return c.json(response);
@@ -5366,9 +5703,11 @@ const respondWebSearchProviderMessagesJson = (c, options) => {
5366
5703
  });
5367
5704
  });
5368
5705
  };
5369
- const createProviderMessagesUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
5706
+ const createProviderMessagesUsageRecorder = (payload, provider, modelConfig, pricingCurrency) => createProviderTokenUsageRecorder({
5370
5707
  endpoint: "provider_messages",
5371
5708
  model: payload.model,
5709
+ pricing: modelConfig?.pricing,
5710
+ pricingCurrency,
5372
5711
  providerName: provider,
5373
5712
  sessionId: parseUserIdMetadata(payload.metadata?.user_id).sessionId
5374
5713
  });
@@ -5454,7 +5793,10 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
5454
5793
  });
5455
5794
  if (isNonStreaming(response)) {
5456
5795
  debugJson(logger, "Non-streaming response from Copilot:", response);
5457
- recordUsage(normalizeOpenAIUsage(response.usage));
5796
+ recordUsage({
5797
+ ...normalizeOpenAIUsage(response.usage),
5798
+ total_nano_aiu: normalizeOptionalToken(response.copilot_usage?.total_nano_aiu)
5799
+ });
5458
5800
  const anthropicResponse = translateToAnthropic(response);
5459
5801
  debugJson(logger, "Translated Anthropic response:", anthropicResponse);
5460
5802
  return c.json(anthropicResponse);
@@ -5474,7 +5816,10 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
5474
5816
  if (rawEvent.data === "[DONE]") break;
5475
5817
  if (!rawEvent.data) continue;
5476
5818
  const chunk = JSON.parse(rawEvent.data);
5477
- if (chunk.usage) usage = normalizeOpenAIUsage(chunk.usage);
5819
+ if (chunk.usage || chunk.copilot_usage) usage = {
5820
+ ...normalizeOpenAIUsage(chunk.usage),
5821
+ total_nano_aiu: normalizeOptionalToken(chunk.copilot_usage?.total_nano_aiu)
5822
+ };
5478
5823
  const events = translateChunkToAnthropicEvents(chunk, streamState);
5479
5824
  for (const event of events) {
5480
5825
  const eventData = JSON.stringify(event);
@@ -5533,7 +5878,10 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
5533
5878
  if (!data) continue;
5534
5879
  debugLazy(logger, () => ["Responses raw stream event:", data]);
5535
5880
  const responseEvent = JSON.parse(data);
5536
- if (responseEvent.type === "response.completed" || responseEvent.type === "response.failed" || responseEvent.type === "response.incomplete") usage = normalizeResponsesUsage(responseEvent.response.usage);
5881
+ if (responseEvent.type === "response.completed" || responseEvent.type === "response.failed" || responseEvent.type === "response.incomplete") usage = {
5882
+ ...normalizeResponsesUsage(responseEvent.response.usage),
5883
+ total_nano_aiu: normalizeOptionalToken(responseEvent.copilot_usage?.total_nano_aiu)
5884
+ };
5537
5885
  const events = translateResponsesStreamEvent(responseEvent, streamState);
5538
5886
  for (const event of events) {
5539
5887
  const eventData = JSON.stringify(event);
@@ -5559,12 +5907,13 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
5559
5907
  recordUsage(usage);
5560
5908
  });
5561
5909
  }
5562
- debugJsonTail(logger, "Non-streaming Responses result:", {
5563
- value: response,
5564
- tailLength: 400
5565
- });
5910
+ debugJson(logger, "Non-streaming Responses result:", response);
5566
5911
  const anthropicResponse = translateResponsesResultToAnthropic(response, { toolSearchName: resolveBridgeToolSearchName(anthropicPayload.tools) });
5567
- recordUsage(normalizeResponsesUsage(response.usage));
5912
+ const responsesResult = response;
5913
+ recordUsage({
5914
+ ...normalizeResponsesUsage(responsesResult.usage),
5915
+ total_nano_aiu: normalizeOptionalToken(responsesResult.copilot_usage?.total_nano_aiu)
5916
+ });
5568
5917
  debugJson(logger, "Translated Anthropic response:", anthropicResponse);
5569
5918
  return c.json(anthropicResponse);
5570
5919
  };
@@ -5759,7 +6108,6 @@ messageRoutes.post("/count_tokens", async (c) => {
5759
6108
  const modelRoutes = new Hono();
5760
6109
  modelRoutes.get("/", async (c) => {
5761
6110
  try {
5762
- if (!state.models) await cacheModels();
5763
6111
  const models = state.models?.data.map((model) => {
5764
6112
  const contextWindow = model.capabilities?.limits?.max_context_window_tokens ?? 0;
5765
6113
  const clientId = toClientModelId(model.id);
@@ -5856,9 +6204,10 @@ async function handleProviderResponsesForProvider(c, options) {
5856
6204
  provider
5857
6205
  });
5858
6206
  compactInputByLatestCompaction(payload);
6207
+ const modelConfig = providerConfig.models?.[payload.model];
5859
6208
  if (providerConfig.name === "codex") {
5860
6209
  const upstreamResponse = await forwardCodexResponses(payload, c.req.raw.headers, providerConfig.baseUrl);
5861
- const recordUsage = createProviderResponsesUsageRecorder(payload, provider);
6210
+ const recordUsage = createProviderResponsesUsageRecorder(payload, provider, modelConfig, providerConfig.pricingCurrency);
5862
6211
  if (payload.stream && isResponsesStream(upstreamResponse)) return streamProviderResponses(c, upstreamResponse, {
5863
6212
  normalizeCodex: true,
5864
6213
  provider,
@@ -5870,7 +6219,7 @@ async function handleProviderResponsesForProvider(c, options) {
5870
6219
  }
5871
6220
  const upstreamResponse = await forwardProviderResponses(providerConfig, payload, c.req.raw.headers);
5872
6221
  if (!upstreamResponse.ok) throw new HTTPError(`Failed to create ${provider} responses`, upstreamResponse);
5873
- const recordUsage = createProviderResponsesUsageRecorder(payload, provider);
6222
+ const recordUsage = createProviderResponsesUsageRecorder(payload, provider, modelConfig, providerConfig.pricingCurrency);
5874
6223
  if (payload.stream) return streamProviderResponses(c, getResponsesEvents(upstreamResponse), {
5875
6224
  normalizeCodex: false,
5876
6225
  provider,
@@ -5879,11 +6228,13 @@ async function handleProviderResponsesForProvider(c, options) {
5879
6228
  recordUsage(normalizeResponsesUsage((await upstreamResponse.clone().json()).usage));
5880
6229
  return createProviderProxyResponse(upstreamResponse);
5881
6230
  }
5882
- const createProviderResponsesUsageRecorder = (payload, provider) => {
6231
+ const createProviderResponsesUsageRecorder = (payload, provider, modelConfig, pricingCurrency) => {
5883
6232
  const sessionAffinity = requestContext.getStore()?.sessionAffinity?.trim() || null;
5884
6233
  return createProviderTokenUsageRecorder({
5885
6234
  endpoint: "responses",
5886
6235
  model: payload.model,
6236
+ pricing: modelConfig?.pricing,
6237
+ pricingCurrency,
5887
6238
  providerName: provider,
5888
6239
  sessionId: sessionAffinity ?? ""
5889
6240
  });
@@ -6068,7 +6419,10 @@ const handleResponses = async (c) => {
6068
6419
  for await (const chunk of response) {
6069
6420
  debugJson(logger$1, "Responses stream chunk:", chunk);
6070
6421
  const parsedEvent = parseResponsesStreamEvent(chunk);
6071
- if (parsedEvent?.type === "response.completed" || parsedEvent?.type === "response.failed" || parsedEvent?.type === "response.incomplete") usage = normalizeResponsesUsage(parsedEvent.response.usage);
6422
+ if (parsedEvent?.type === "response.completed" || parsedEvent?.type === "response.failed" || parsedEvent?.type === "response.incomplete") usage = {
6423
+ ...normalizeResponsesUsage(parsedEvent.response.usage),
6424
+ total_nano_aiu: normalizeOptionalToken(parsedEvent.copilot_usage?.total_nano_aiu)
6425
+ };
6072
6426
  const processedData = fixStreamIds(chunk.data ?? "", chunk.event, idTracker);
6073
6427
  await stream.writeSSE({
6074
6428
  id: chunk.id,
@@ -6083,8 +6437,12 @@ const handleResponses = async (c) => {
6083
6437
  value: response,
6084
6438
  tailLength: 400
6085
6439
  });
6086
- recordUsage(normalizeResponsesUsage(response.usage));
6087
- return c.json(response);
6440
+ const result = response;
6441
+ recordUsage({
6442
+ ...normalizeResponsesUsage(result.usage),
6443
+ total_nano_aiu: normalizeOptionalToken(result.copilot_usage?.total_nano_aiu)
6444
+ });
6445
+ return c.json(result);
6088
6446
  };
6089
6447
  const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
6090
6448
  const isStreamingRequested = (payload) => Boolean(payload.stream);
@@ -6254,4 +6612,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
6254
6612
  //#endregion
6255
6613
  export { server };
6256
6614
 
6257
- //# sourceMappingURL=server-34rnRg4k.js.map
6615
+ //# sourceMappingURL=server-7U9OZLf0.js.map