cost-calculation-priority.test.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { describe, expect, test } from "vitest";
  2. import { calculateRequestCost } from "@/lib/utils/cost-calculation";
  3. import type { ModelPriceData } from "@/types/model-price";
  4. function makePriceData(overrides: Partial<ModelPriceData> = {}): ModelPriceData {
  5. return {
  6. mode: "responses",
  7. input_cost_per_token: 1,
  8. output_cost_per_token: 10,
  9. cache_read_input_token_cost: 0.1,
  10. input_cost_per_token_priority: 2,
  11. output_cost_per_token_priority: 20,
  12. cache_read_input_token_cost_priority: 0.2,
  13. ...overrides,
  14. };
  15. }
  16. describe("calculateRequestCost priority service tier", () => {
  17. test("uses priority pricing fields when priority service tier is applied", () => {
  18. const cost = calculateRequestCost(
  19. { input_tokens: 2, output_tokens: 3, cache_read_input_tokens: 5 },
  20. makePriceData(),
  21. 1,
  22. false,
  23. true
  24. );
  25. expect(Number(cost.toString())).toBe(65);
  26. });
  27. test("falls back to regular pricing when priority fields are absent", () => {
  28. const cost = calculateRequestCost(
  29. { input_tokens: 2, output_tokens: 3, cache_read_input_tokens: 5 },
  30. makePriceData({
  31. input_cost_per_token_priority: undefined,
  32. output_cost_per_token_priority: undefined,
  33. cache_read_input_token_cost_priority: undefined,
  34. }),
  35. 1,
  36. false,
  37. true
  38. );
  39. expect(Number(cost.toString())).toBe(32.5);
  40. });
  41. test("uses priority long-context pricing fields when available", () => {
  42. const cost = calculateRequestCost(
  43. {
  44. input_tokens: 272001,
  45. output_tokens: 2,
  46. cache_read_input_tokens: 10,
  47. },
  48. makePriceData({
  49. mode: "responses",
  50. model_family: "gpt",
  51. input_cost_per_token_above_272k_tokens: 5,
  52. output_cost_per_token_above_272k_tokens: 50,
  53. cache_read_input_token_cost_above_272k_tokens: 0.5,
  54. input_cost_per_token_above_272k_tokens_priority: 7,
  55. output_cost_per_token_above_272k_tokens_priority: 70,
  56. cache_read_input_token_cost_above_272k_tokens_priority: 0.7,
  57. }),
  58. 1,
  59. false,
  60. true
  61. );
  62. expect(Number(cost.toString())).toBe(1904154);
  63. });
  64. test("falls back to regular long-context pricing when priority long-context fields are absent", () => {
  65. const cost = calculateRequestCost(
  66. {
  67. input_tokens: 272001,
  68. output_tokens: 2,
  69. cache_read_input_tokens: 10,
  70. },
  71. makePriceData({
  72. mode: "responses",
  73. model_family: "gpt",
  74. input_cost_per_token_above_272k_tokens: 5,
  75. output_cost_per_token_above_272k_tokens: 50,
  76. cache_read_input_token_cost_above_272k_tokens: 0.5,
  77. input_cost_per_token_above_272k_tokens_priority: undefined,
  78. output_cost_per_token_above_272k_tokens_priority: undefined,
  79. cache_read_input_token_cost_above_272k_tokens_priority: undefined,
  80. }),
  81. 1,
  82. false,
  83. true
  84. );
  85. expect(Number(cost.toString())).toBe(1360110);
  86. });
  87. test("uses priority long-context fields by schema, not by model name", () => {
  88. const cost = calculateRequestCost(
  89. {
  90. input_tokens: 272001,
  91. output_tokens: 2,
  92. },
  93. makePriceData({
  94. mode: "responses",
  95. model_family: undefined,
  96. input_cost_per_token_above_272k_tokens: undefined,
  97. output_cost_per_token_above_272k_tokens: undefined,
  98. input_cost_per_token_above_272k_tokens_priority: 7,
  99. output_cost_per_token_above_272k_tokens_priority: 70,
  100. }),
  101. 1,
  102. false,
  103. true
  104. );
  105. expect(Number(cost.toString())).toBe(1904147);
  106. });
  107. });