fix(pricing): handle date-stamped 4.6 thinking model IDs

This commit is contained in:
Tam Nhu Tran
2026-03-03 23:08:04 +07:00
parent 9a7ca3f1c0
commit d31f85b0d4
2 changed files with 23 additions and 3 deletions
+7 -3
View File
@@ -734,7 +734,7 @@ const UNKNOWN_MODEL_PRICING: ModelPricing = {
/** /**
* Normalize model name for matching * Normalize model name for matching
* Handles variations like provider prefixes, case differences, and date suffixes * Handles variations like provider prefixes and case differences
*/ */
function normalizeModelName(model: string): string { function normalizeModelName(model: string): string {
// Remove provider prefixes (e.g., "anthropic/claude-..." -> "claude-...") // Remove provider prefixes (e.g., "anthropic/claude-..." -> "claude-...")
@@ -747,10 +747,14 @@ function normalizeModelName(model: string): string {
/** /**
* Strip trailing date suffix from model name (e.g., "-20260101") * Strip trailing date suffix from model name (e.g., "-20260101")
* Only strips 8-digit YYYYMMDD suffixes at the end of the string. * Claude session IDs can place dates either at the end or before "-thinking".
*/ */
function stripDateSuffix(model: string): string { function stripDateSuffix(model: string): string {
return model.replace(/-\d{8}$/, ''); if (!model.startsWith('claude-')) {
return model;
}
return model.replace(/-\d{8}(?=-thinking(?:$|:))/g, '').replace(/-\d{8}(?=$|:)/g, '');
} }
const NORMALIZED_PRICING_REGISTRY: Record<string, ModelPricing> = Object.entries( const NORMALIZED_PRICING_REGISTRY: Record<string, ModelPricing> = Object.entries(
+16
View File
@@ -120,6 +120,18 @@ describe('model-pricing', () => {
expect(opus46.inputPerMillion).toBe(5.0); expect(opus46.inputPerMillion).toBe(5.0);
expect(opus46.outputPerMillion).toBe(25.0); expect(opus46.outputPerMillion).toBe(25.0);
}); });
it('should match date-stamped thinking Claude Opus 4.6 to correct pricing', () => {
const opus46 = getModelPricing('claude-opus-4-6-20260101-thinking');
expect(opus46.inputPerMillion).toBe(5.0);
expect(opus46.outputPerMillion).toBe(25.0);
});
it('should match provider-prefixed date-stamped thinking model to correct pricing', () => {
const opus46 = getModelPricing('anthropic/claude-opus-4-6-20260101-thinking');
expect(opus46.inputPerMillion).toBe(5.0);
expect(opus46.outputPerMillion).toBe(25.0);
});
}); });
describe('calculateCost', () => { describe('calculateCost', () => {
@@ -209,6 +221,10 @@ describe('model-pricing', () => {
expect(hasCustomPricing('qwen3-coder')).toBe(true); expect(hasCustomPricing('qwen3-coder')).toBe(true);
}); });
it('should not treat date-stamped non-Claude IDs as deterministic aliases', () => {
expect(hasCustomPricing('qwen3-32b-20260101')).toBe(false);
});
it('should return false for unknown models', () => { it('should return false for unknown models', () => {
expect(hasCustomPricing('unknown-model-xyz')).toBe(false); expect(hasCustomPricing('unknown-model-xyz')).toBe(false);
}); });