diff --git a/docs/plans/2026-02-23-unify-cost-calculation-design.md b/docs/plans/2026-02-23-unify-cost-calculation-design.md
index 76a91505..38380aa6 100644
--- a/docs/plans/2026-02-23-unify-cost-calculation-design.md
+++ b/docs/plans/2026-02-23-unify-cost-calculation-design.md
@@ -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
diff --git a/docs/plans/2026-02-23-unify-cost-calculation.md b/docs/plans/2026-02-23-unify-cost-calculation.md
index ead3814b..aa6dfc43 100644
--- a/docs/plans/2026-02-23-unify-cost-calculation.md
+++ b/docs/plans/2026-02-23-unify-cost-calculation.md
@@ -10,6 +10,8 @@
---
+## Tasks
+
### Task 1: Create the shared pricing module with tests
**Files:**
diff --git a/src/renderer/components/chat/SessionContextPanel/components/SessionContextHeader.tsx b/src/renderer/components/chat/SessionContextPanel/components/SessionContextHeader.tsx
index ef69d539..0c5cd0dd 100644
--- a/src/renderer/components/chat/SessionContextPanel/components/SessionContextHeader.tsx
+++ b/src/renderer/components/chat/SessionContextPanel/components/SessionContextHeader.tsx
@@ -134,22 +134,22 @@ export const SessionContextHeader = ({
{formatCostUsd(sessionMetrics.costUsd)}
- (parent only
- {onViewReport ? (
-
- ·
-
- )
-
- ) : (
- )
- )}
+
+ {' (parent only'}
+ {onViewReport && (
+ <>
+ {' · '}
+
+ >
+ )}
+ {')'}
+
)}
diff --git a/src/shared/utils/pricing.ts b/src/shared/utils/pricing.ts
index 0e3b800a..28800696 100644
--- a/src/shared/utils/pricing.ts
+++ b/src/shared/utils/pricing.ts
@@ -22,19 +22,28 @@ export interface DisplayPricing {
const TIER_THRESHOLD = 200_000;
-const pricingMap = pricingData as Record;
+const PRICING_MAP = pricingData as Record;
-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();
+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;
diff --git a/test/main/utils/costCalculation.test.ts b/test/main/utils/costCalculation.test.ts
index 1843daea..2ea481a3 100644
--- a/test/main/utils/costCalculation.test.ts
+++ b/test/main/utils/costCalculation.test.ts
@@ -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',
diff --git a/test/shared/utils/pricing.test.ts b/test/shared/utils/pricing.test.ts
index 7b872cb7..f8a807b9 100644
--- a/test/shared/utils/pricing.test.ts
+++ b/test/shared/utils/pricing.test.ts
@@ -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(