model-utils.test.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /**
  2. * @fileoverview Tests for token and model utility functions
  3. */
  4. import {
  5. getMaxTokensForModel,
  6. calculateTokenDistribution,
  7. ModelInfo,
  8. ApiConfig,
  9. DEFAULT_THINKING_MODEL_MAX_TOKENS,
  10. } from "../model-utils"
  11. describe("Model utility functions", () => {
  12. describe("getMaxTokensForModel", () => {
  13. /**
  14. * Testing the specific fix in commit cc79178f:
  15. * For thinking models, use apiConfig.modelMaxTokens if available,
  16. * otherwise fall back to 8192 (not modelInfo.maxTokens)
  17. */
  18. it("should return apiConfig.modelMaxTokens for thinking models when provided", () => {
  19. const modelInfo: ModelInfo = {
  20. thinking: true,
  21. maxTokens: 8000,
  22. }
  23. const apiConfig: ApiConfig = {
  24. modelMaxTokens: 4000,
  25. }
  26. expect(getMaxTokensForModel(modelInfo, apiConfig)).toBe(4000)
  27. })
  28. it("should return 16_384 for thinking models when modelMaxTokens not provided", () => {
  29. const modelInfo: ModelInfo = {
  30. thinking: true,
  31. maxTokens: 8000,
  32. }
  33. const apiConfig: ApiConfig = {}
  34. // This tests the specific fix: now using DEFAULT_THINKING_MODEL_MAX_TOKENS instead of falling back to modelInfo.maxTokens
  35. expect(getMaxTokensForModel(modelInfo, apiConfig)).toBe(DEFAULT_THINKING_MODEL_MAX_TOKENS)
  36. })
  37. it("should return 16_384 for thinking models when apiConfig is undefined", () => {
  38. const modelInfo: ModelInfo = {
  39. thinking: true,
  40. maxTokens: 8000,
  41. }
  42. expect(getMaxTokensForModel(modelInfo, undefined)).toBe(DEFAULT_THINKING_MODEL_MAX_TOKENS)
  43. })
  44. it("should return modelInfo.maxTokens for non-thinking models", () => {
  45. const modelInfo: ModelInfo = {
  46. thinking: false,
  47. maxTokens: 8000,
  48. }
  49. const apiConfig: ApiConfig = {
  50. modelMaxTokens: 4000,
  51. }
  52. expect(getMaxTokensForModel(modelInfo, apiConfig)).toBe(8000)
  53. })
  54. it("should return undefined for non-thinking models with undefined maxTokens", () => {
  55. const modelInfo: ModelInfo = {
  56. thinking: false,
  57. }
  58. const apiConfig: ApiConfig = {
  59. modelMaxTokens: 4000,
  60. }
  61. expect(getMaxTokensForModel(modelInfo, apiConfig)).toBeUndefined()
  62. })
  63. it("should return undefined when modelInfo is undefined", () => {
  64. const apiConfig: ApiConfig = {
  65. modelMaxTokens: 4000,
  66. }
  67. expect(getMaxTokensForModel(undefined, apiConfig)).toBeUndefined()
  68. })
  69. })
  70. describe("calculateTokenDistribution", () => {
  71. it("should calculate token distribution correctly", () => {
  72. const contextWindow = 10000
  73. const contextTokens = 5000
  74. const maxTokens = 2000
  75. const result = calculateTokenDistribution(contextWindow, contextTokens, maxTokens)
  76. expect(result.reservedForOutput).toBe(maxTokens)
  77. expect(result.availableSize).toBe(3000) // 10000 - 5000 - 2000
  78. // Percentages should sum to 100%
  79. expect(Math.round(result.currentPercent + result.reservedPercent + result.availablePercent)).toBe(100)
  80. })
  81. it("should default to 20% of context window when maxTokens not provided", () => {
  82. const contextWindow = 10000
  83. const contextTokens = 5000
  84. const result = calculateTokenDistribution(contextWindow, contextTokens)
  85. expect(result.reservedForOutput).toBe(2000) // 20% of 10000
  86. expect(result.availableSize).toBe(3000) // 10000 - 5000 - 2000
  87. })
  88. it("should handle negative or zero inputs by using positive fallbacks", () => {
  89. const result = calculateTokenDistribution(-1000, -500)
  90. expect(result.currentPercent).toBe(0)
  91. expect(result.reservedPercent).toBe(0)
  92. expect(result.availablePercent).toBe(0)
  93. expect(result.reservedForOutput).toBe(0) // With negative inputs, both context window and tokens become 0, so 20% of 0 is 0
  94. expect(result.availableSize).toBe(0)
  95. })
  96. it("should handle zero total tokens without division by zero errors", () => {
  97. const result = calculateTokenDistribution(0, 0, 0)
  98. expect(result.currentPercent).toBe(0)
  99. expect(result.reservedPercent).toBe(0)
  100. expect(result.availablePercent).toBe(0)
  101. expect(result.reservedForOutput).toBe(0)
  102. expect(result.availableSize).toBe(0)
  103. })
  104. })
  105. })