fix(usage-cost): only flag catalog-default zeros, preserve operator-configured $0

Address review: distinguish unknown pricing from an intentional free price. A
turn's all-zero cost is treated as unknown (counted toward missingCostEntries)
only when the operator did NOT explicitly configure the model's price under
models.providers -- i.e. the zero is a generated-catalog default (codex/gpt-5.x),
not a deliberate $0. Operator-configured zero-cost models keep reporting a
complete $0.

Adds resolveConfiguredModelCost() to read config-only pricing, and regression
tests for both paths (unconfigured unknown -> missing; configured free -> $0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Zelbel
2026-05-24 15:40:34 +02:00
committed by Peter Steinberger
parent 6e85869161
commit 16702496c6
3 changed files with 83 additions and 13 deletions

View File

@@ -298,6 +298,22 @@ export function resolveModelCostConfigFingerprint(config?: OpenClawConfig): stri
});
}
// Returns model pricing ONLY when the operator explicitly configured it under
// `models.providers` in their OpenClaw config. Unlike resolveModelCostConfig this
// ignores the generated model catalog (models.json) and the gateway pricing cache, so
// callers can tell an intentional operator-set price (e.g. a deliberately free local
// model priced at 0) apart from a price the catalog merely defaulted to zero.
export function resolveConfiguredModelCost(params: {
provider?: string;
model?: string;
config?: OpenClawConfig;
}): ModelCostConfig | undefined {
return (
findConfiguredProviderCost({ ...params, allowPluginNormalization: false }) ??
findConfiguredProviderCost(params)
);
}
export function resolveModelCostConfig(params: {
provider?: string;
model?: string;