|
| 1 | +// This test directly tests the logic of the ContextWindowProgress component calculations |
| 2 | +// without needing to render the full component |
| 3 | +import { describe, test, expect } from "@jest/globals" |
| 4 | +import { calculateTokenDistribution } from "../utils/model-utils" |
| 5 | + |
| 6 | +export {} // This makes the file a proper TypeScript module |
| 7 | + |
| 8 | +describe("ContextWindowProgress Logic", () => { |
| 9 | + // Using the shared utility function from model-utils.ts instead of reimplementing it |
| 10 | + |
| 11 | + test("calculates correct token distribution with default 20% reservation", () => { |
| 12 | + const contextWindow = 4000 |
| 13 | + const contextTokens = 1000 |
| 14 | + |
| 15 | + const result = calculateTokenDistribution(contextWindow, contextTokens) |
| 16 | + |
| 17 | + // Expected calculations: |
| 18 | + // reservedForOutput = 0.2 * 4000 = 800 |
| 19 | + // availableSize = 4000 - 1000 - 800 = 2200 |
| 20 | + // total = 1000 + 800 + 2200 = 4000 |
| 21 | + expect(result.reservedForOutput).toBe(800) |
| 22 | + expect(result.availableSize).toBe(2200) |
| 23 | + |
| 24 | + // Check percentages |
| 25 | + expect(result.currentPercent).toBeCloseTo(25) // 1000/4000 * 100 = 25% |
| 26 | + expect(result.reservedPercent).toBeCloseTo(20) // 800/4000 * 100 = 20% |
| 27 | + expect(result.availablePercent).toBeCloseTo(55) // 2200/4000 * 100 = 55% |
| 28 | + |
| 29 | + // Verify percentages sum to 100% |
| 30 | + expect(result.currentPercent + result.reservedPercent + result.availablePercent).toBeCloseTo(100) |
| 31 | + }) |
| 32 | + |
| 33 | + test("uses provided maxTokens when available instead of default calculation", () => { |
| 34 | + const contextWindow = 4000 |
| 35 | + const contextTokens = 1000 |
| 36 | + |
| 37 | + // First calculate with default 20% reservation (no maxTokens provided) |
| 38 | + const defaultResult = calculateTokenDistribution(contextWindow, contextTokens) |
| 39 | + |
| 40 | + // Then calculate with custom maxTokens value |
| 41 | + const customMaxTokens = 1500 // Custom maxTokens instead of default 20% |
| 42 | + const customResult = calculateTokenDistribution(contextWindow, contextTokens, customMaxTokens) |
| 43 | + |
| 44 | + // VERIFY MAXTOKEN PROP EFFECT: Custom maxTokens should be used directly instead of 20% calculation |
| 45 | + const defaultReserved = Math.ceil(contextWindow * 0.2) // 800 tokens (20% of 4000) |
| 46 | + expect(defaultResult.reservedForOutput).toBe(defaultReserved) |
| 47 | + expect(customResult.reservedForOutput).toBe(customMaxTokens) // Should use exact provided value |
| 48 | + |
| 49 | + // Explicitly confirm the tooltip content would be different |
| 50 | + const defaultTooltip = `Reserved for model response: ${defaultReserved} tokens` |
| 51 | + const customTooltip = `Reserved for model response: ${customMaxTokens} tokens` |
| 52 | + expect(defaultTooltip).not.toBe(customTooltip) |
| 53 | + |
| 54 | + // Verify the effect on available space |
| 55 | + expect(customResult.availableSize).toBe(4000 - 1000 - 1500) // 1500 tokens available |
| 56 | + expect(defaultResult.availableSize).toBe(4000 - 1000 - 800) // 2200 tokens available |
| 57 | + |
| 58 | + // Verify the effect on percentages |
| 59 | + // With custom maxTokens (1500), the reserved percentage should be higher |
| 60 | + expect(defaultResult.reservedPercent).toBeCloseTo(20) // 800/4000 * 100 = 20% |
| 61 | + expect(customResult.reservedPercent).toBeCloseTo(37.5) // 1500/4000 * 100 = 37.5% |
| 62 | + |
| 63 | + // Verify percentages still sum to 100% |
| 64 | + expect(customResult.currentPercent + customResult.reservedPercent + customResult.availablePercent).toBeCloseTo( |
| 65 | + 100, |
| 66 | + ) |
| 67 | + }) |
| 68 | + |
| 69 | + test("handles negative input values", () => { |
| 70 | + const contextWindow = 4000 |
| 71 | + const contextTokens = -500 // Negative tokens should be handled gracefully |
| 72 | + |
| 73 | + const result = calculateTokenDistribution(contextWindow, contextTokens) |
| 74 | + |
| 75 | + // Expected calculations: |
| 76 | + // safeContextTokens = Math.max(0, -500) = 0 |
| 77 | + // reservedForOutput = 0.2 * 4000 = 800 |
| 78 | + // availableSize = 4000 - 0 - 800 = 3200 |
| 79 | + // total = 0 + 800 + 3200 = 4000 |
| 80 | + expect(result.currentPercent).toBeCloseTo(0) // 0/4000 * 100 = 0% |
| 81 | + expect(result.reservedPercent).toBeCloseTo(20) // 800/4000 * 100 = 20% |
| 82 | + expect(result.availablePercent).toBeCloseTo(80) // 3200/4000 * 100 = 80% |
| 83 | + }) |
| 84 | + |
| 85 | + test("handles zero context window gracefully", () => { |
| 86 | + const contextWindow = 0 |
| 87 | + const contextTokens = 1000 |
| 88 | + |
| 89 | + const result = calculateTokenDistribution(contextWindow, contextTokens) |
| 90 | + |
| 91 | + // With zero context window, everything should be zero |
| 92 | + expect(result.reservedForOutput).toBe(0) |
| 93 | + expect(result.availableSize).toBe(0) |
| 94 | + |
| 95 | + // The percentages maintain total of 100% even with zero context window |
| 96 | + // due to how the division handles this edge case |
| 97 | + const totalPercentage = result.currentPercent + result.reservedPercent + result.availablePercent |
| 98 | + expect(totalPercentage).toBeCloseTo(100) |
| 99 | + }) |
| 100 | + |
| 101 | + test("handles case where tokens exceed context window", () => { |
| 102 | + const contextWindow = 4000 |
| 103 | + const contextTokens = 5000 // More tokens than the window size |
| 104 | + |
| 105 | + const result = calculateTokenDistribution(contextWindow, contextTokens) |
| 106 | + |
| 107 | + // Expected calculations: |
| 108 | + // reservedForOutput = 0.2 * 4000 = 800 |
| 109 | + // availableSize = Math.max(0, 4000 - 5000 - 800) = 0 |
| 110 | + expect(result.reservedForOutput).toBe(800) |
| 111 | + expect(result.availableSize).toBe(0) |
| 112 | + |
| 113 | + // Percentages should be calculated based on total (5000 + 800 + 0 = 5800) |
| 114 | + expect(result.currentPercent).toBeCloseTo((5000 / 5800) * 100) |
| 115 | + expect(result.reservedPercent).toBeCloseTo((800 / 5800) * 100) |
| 116 | + expect(result.availablePercent).toBeCloseTo(0) |
| 117 | + |
| 118 | + // Verify percentages sum to 100% |
| 119 | + expect(result.currentPercent + result.reservedPercent + result.availablePercent).toBeCloseTo(100) |
| 120 | + }) |
| 121 | +}) |
0 commit comments