mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-07-27 01:45:00 +00:00
fix(report): only exact zero-rate overrides suppress the unpriced flag
getModelCosts resolves exact overrides before any table hit, so an exact zero-rate override provably priced the model and means free. Prefix and case-insensitive overrides resolve after table hits: a zero-rate stub shadowed by one still reports $0 from the stub, so it stays flagged. Refs #638
This commit is contained in:
parent
e6162f6b50
commit
bf6eee00f3
2 changed files with 16 additions and 8 deletions
|
|
@ -692,17 +692,19 @@ function hasBillableRate(costs: ModelCosts): boolean {
|
|||
|| costs.cacheReadCostPerToken > 0
|
||||
}
|
||||
|
||||
// The user-override lookup from getModelCosts, in isolation. Lets the unpriced
|
||||
// detector distinguish "explicitly declared free by the user" (a zero-rate
|
||||
// override) from a zero-rate LiteLLM stub, which means "listed but unknown
|
||||
// price" and must still be flagged.
|
||||
function userPriceOverrideFor(model: string): ModelCosts | null {
|
||||
// Exact-override lookup with the same key derivation getModelCosts uses. Lets
|
||||
// the unpriced detector distinguish "explicitly declared free by the user" (a
|
||||
// zero-rate override) from a zero-rate LiteLLM stub, which means "listed but
|
||||
// unknown price" and must still be flagged. Only the EXACT override form is
|
||||
// consulted: getModelCosts checks it before any table hit, so when one exists
|
||||
// it is provably what priced the model. Prefix and case-insensitive overrides
|
||||
// resolve AFTER table hits and so cannot prove the $0 was intentional; a
|
||||
// zero-rate stub shadowed by one still gets flagged (the honest direction).
|
||||
function exactPriceOverrideFor(model: string): ModelCosts | null {
|
||||
const withPrefix = model.replace(/@.*$/, '').replace(/-\d{8}$/, '')
|
||||
const canonicalName = getCanonicalName(model)
|
||||
const canonical = resolveAlias(canonicalName)
|
||||
return getPriceOverrideExact(model, withPrefix, canonicalName, canonical)
|
||||
?? getPriceOverridePrefix(canonical)
|
||||
?? getPriceOverrideCaseInsensitive(canonical, withPrefix)
|
||||
}
|
||||
|
||||
// Render-time unpriced detection (#638): flag aggregated model rows that carry
|
||||
|
|
@ -735,7 +737,7 @@ export function findUnpricedModels(
|
|||
if (getLocalSavingsBaseline(model)) continue
|
||||
const costs = getModelCosts(model)
|
||||
if (costs && hasBillableRate(costs)) continue
|
||||
if (costs && userPriceOverrideFor(model)) continue
|
||||
if (costs && exactPriceOverrideFor(model)) continue
|
||||
out.push({ model, calls: row.calls, tokens })
|
||||
}
|
||||
return out.sort((a, b) => (b.tokens - a.tokens) || (b.calls - a.calls)
|
||||
|
|
|
|||
|
|
@ -736,6 +736,12 @@ describe('findUnpricedModels', () => {
|
|||
// An explicit user override at zero rates means "this model is free".
|
||||
setPriceOverrides({ 'zz-zero-stub-model': { input: 0, output: 0 } })
|
||||
expect(findUnpricedModels(rows)).toEqual([])
|
||||
|
||||
// A prefix override cannot prove intent: getModelCosts resolves table
|
||||
// hits before prefix overrides, so the $0 came from the stub, not the
|
||||
// user. Still flagged.
|
||||
setPriceOverrides({ 'zz-zero-stub': { input: 0, output: 0 } })
|
||||
expect(findUnpricedModels(rows)).toHaveLength(1)
|
||||
} finally {
|
||||
delete process.env['CODEBURN_CACHE_DIR']
|
||||
await rm(cacheRoot, { recursive: true, force: true })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue