fix(review): address CodeRabbit and Gemini review comments

- Design doc: update "No UI changes" to reflect cost disclaimer
- Plan doc: fix MD001 heading level jump (### after #)
- pricing.ts: rename to PRICING_MAP, add isLiteLLMPricing type guard,
  pre-compute LOWERCASE_KEY_MAP for O(1) case-insensitive lookups
- SessionContextHeader: simplify cost disclaimer JSX into single span
- Tests: fix no-empty-function lint (() => {} → () => undefined)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul Holstein 2026-02-23 12:49:05 -05:00
parent c507a4f9d5
commit 5ca3fc9008
6 changed files with 42 additions and 36 deletions

View file

@ -62,7 +62,7 @@ Create a single shared pricing module that both processes import.
- Report costs become more accurate (tiered pricing, 206 models instead of 6)
- Cost numbers between chat view and Session Report now agree exactly
- No UI changes — same components, same layout
- Small UI change: Visible Context header adds a "parent only · view full cost" action when available
## Out of Scope

View file

@ -10,6 +10,8 @@
---
## Tasks
### Task 1: Create the shared pricing module with tests
**Files:**

View file

@ -134,22 +134,22 @@ export const SessionContextHeader = ({
<span className="font-medium tabular-nums" style={{ color: COLOR_TEXT_SECONDARY }}>
{formatCostUsd(sessionMetrics.costUsd)}
</span>
<span style={{ color: COLOR_TEXT_MUTED }}> (parent only</span>
{onViewReport ? (
<span>
<span style={{ color: COLOR_TEXT_MUTED }}> · </span>
<button
onClick={onViewReport}
className="underline"
style={{ color: COLOR_TEXT_SECONDARY }}
>
view full cost
</button>
<span style={{ color: COLOR_TEXT_MUTED }}>)</span>
</span>
) : (
<span style={{ color: COLOR_TEXT_MUTED }}>)</span>
)}
<span style={{ color: COLOR_TEXT_MUTED }}>
{' (parent only'}
{onViewReport && (
<>
{' · '}
<button
onClick={onViewReport}
className="underline"
style={{ color: COLOR_TEXT_SECONDARY }}
>
view full cost
</button>
</>
)}
{')'}
</span>
</div>
)}
</div>

View file

@ -22,19 +22,28 @@ export interface DisplayPricing {
const TIER_THRESHOLD = 200_000;
const pricingMap = pricingData as Record<string, unknown>;
const PRICING_MAP = pricingData as Record<string, unknown>;
function tryGetPricing(key: string): LiteLLMPricing | null {
const entry = pricingMap[key];
if (
entry &&
// Pre-compute lowercase key map for O(1) case-insensitive lookups
const LOWERCASE_KEY_MAP = new Map<string, string>();
for (const key of Object.keys(PRICING_MAP)) {
if (!LOWERCASE_KEY_MAP.has(key.toLowerCase())) {
LOWERCASE_KEY_MAP.set(key.toLowerCase(), key);
}
}
function isLiteLLMPricing(entry: unknown): entry is LiteLLMPricing {
return (
!!entry &&
typeof entry === 'object' &&
'input_cost_per_token' in entry &&
'output_cost_per_token' in entry
) {
return entry as LiteLLMPricing;
}
return null;
);
}
function tryGetPricing(key: string): LiteLLMPricing | null {
const entry = PRICING_MAP[key];
return isLiteLLMPricing(entry) ? entry : null;
}
export function getPricing(modelName: string): LiteLLMPricing | null {
@ -42,14 +51,9 @@ export function getPricing(modelName: string): LiteLLMPricing | null {
if (exact) return exact;
const lowerName = modelName.toLowerCase();
const lower = tryGetPricing(lowerName);
if (lower) return lower;
for (const key of Object.keys(pricingMap)) {
if (key.toLowerCase() === lowerName) {
const match = tryGetPricing(key);
if (match) return match;
}
const originalKey = LOWERCASE_KEY_MAP.get(lowerName);
if (originalKey) {
return tryGetPricing(originalKey);
}
return null;

View file

@ -84,7 +84,7 @@ describe('Cost Calculation', () => {
});
it('should return 0 cost when model pricing not found', () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
const messages: ParsedMessage[] = [
{
type: 'assistant',

View file

@ -55,7 +55,7 @@ describe('Shared Pricing Module', () => {
});
it('should return 0 for unknown models', () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
const cost = calculateMessageCost('unknown-model', 1000, 500, 0, 0);
expect(cost).toBe(0);
expect(warnSpy).toHaveBeenCalledWith(