mirror of
https://github.com/HeyPuter/puter.git
synced 2026-09-22 21:26:04 +00:00
fix: metering service alerts + missing claude costs (#2058)
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test (20.x) (push) Has been cancelled
test / test (22.x) (push) Has been cancelled
test / backend (node env, api-test) (22.x) (push) Has been cancelled
test / puterjs (browser env, playwright) (22.x) (push) Has been cancelled
test / puterjs (node env, vitest) (22.x) (push) Has been cancelled
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test (20.x) (push) Has been cancelled
test / test (22.x) (push) Has been cancelled
test / backend (node env, api-test) (22.x) (push) Has been cancelled
test / puterjs (browser env, playwright) (22.x) (push) Has been cancelled
test / puterjs (node env, vitest) (22.x) (push) Has been cancelled
* fix: missing haiku costs, updating opus 4.5 id to match documentation * fix: improve alert logic for metering service misses
This commit is contained in:
@@ -370,8 +370,8 @@ class ClaudeService extends BaseService {
|
||||
models_ () {
|
||||
return [
|
||||
{
|
||||
id: 'claude-opus-4-5',
|
||||
aliases: ['claude-opus-4-5-latest', 'claude-opus-4.5'],
|
||||
id: 'claude-opus-4-5-20251101',
|
||||
aliases: ['claude-opus-4-5-latest', 'claude-opus-4-5', 'claude-opus-4.5'],
|
||||
name: 'Claude Opus 4.5',
|
||||
cost: {
|
||||
currency: 'usd-cents',
|
||||
|
||||
@@ -30,7 +30,7 @@ export class MeteringService {
|
||||
this.batchIncrementUsages(actor, Object.entries(trackedUsageObject).map(([usageKind, amount]) => ({
|
||||
usageType: `${modelPrefix}:${usageKind}`,
|
||||
usageAmount: amount,
|
||||
costOverride: costsOverrides?.[usageKind as keyof T],
|
||||
costOverride: costsOverrides?.[usageKind as keyof T] || undefined,
|
||||
})));
|
||||
}
|
||||
|
||||
@@ -79,9 +79,11 @@ export class MeteringService {
|
||||
const currentMonth = this.#getMonthYearString();
|
||||
|
||||
return this.#superUserService.sudo(async () => {
|
||||
const totalCost = (costOverride ?? (COST_MAPS[usageType as keyof typeof COST_MAPS] || 0) * usageAmount) || 0; // TODO DS: apply our policy discounts here eventually
|
||||
|
||||
if ( COST_MAPS[usageType as keyof typeof COST_MAPS] !== 0 && totalCost === 0 && costOverride === undefined ) {
|
||||
const mappedCost = COST_MAPS[usageType as keyof typeof COST_MAPS];
|
||||
const totalCost = (costOverride ?? ((mappedCost || 0) * usageAmount));
|
||||
|
||||
if ( totalCost === 0 && mappedCost !== 0 && costOverride !== 0 ) {
|
||||
// could be something is off, there are some models that cost nothing from openrouter, but then our overrides should not be undefined, so will flag
|
||||
this.#alarmService.create('metering-service-0-cost-warning', 'potential abuse vector', {
|
||||
actor,
|
||||
@@ -227,11 +229,12 @@ export class MeteringService {
|
||||
continue; // skip invalid entries
|
||||
}
|
||||
|
||||
const totalCost = (costOverride ?? (COST_MAPS[usageType as keyof typeof COST_MAPS] || 0) * usageAmount) || 0;
|
||||
const mappedCost = COST_MAPS[usageType as keyof typeof COST_MAPS];
|
||||
const totalCost = costOverride ?? ((mappedCost || 0) * usageAmount);
|
||||
totalBatchCost += totalCost;
|
||||
|
||||
// Check for zero cost warning (only flag once per batch)
|
||||
if ( !hasZeroCostWarning && COST_MAPS[usageType as keyof typeof COST_MAPS] !== 0 && totalCost === 0 && costOverride === undefined ) {
|
||||
if ( !hasZeroCostWarning && totalCost === 0 && mappedCost !== 0 && costOverride !== 0 ) {
|
||||
hasZeroCostWarning = true;
|
||||
this.#alarmService.create('metering-service-0-cost-warning', 'potential abuse vector', {
|
||||
actor,
|
||||
|
||||
@@ -19,18 +19,19 @@
|
||||
|
||||
export const CLAUDE_COST_MAP = {
|
||||
// Claude Opus 4.5
|
||||
'claude:claude-opus-4-5:input_tokens': 500,
|
||||
'claude:claude-opus-4-5:ephemeral_5m_input_tokens': 500 * 1.25,
|
||||
'claude:claude-opus-4-5:ephemeral_1h_input_tokens': 500 * 2,
|
||||
'claude:claude-opus-4-5:cache_read_input_tokens': 500 * 0.1,
|
||||
'claude:claude-opus-4-5:output_tokens': 2500,
|
||||
|
||||
'claude:claude-opus-4-5-20251101:input_tokens': 500,
|
||||
'claude:claude-opus-4-5-20251101:ephemeral_5m_input_tokens': 500 * 1.25,
|
||||
'claude:claude-opus-4-5-20251101:ephemeral_1h_input_tokens': 500 * 2,
|
||||
'claude:claude-opus-4-5-20251101:cache_read_input_tokens': 500 * 0.1,
|
||||
'claude:claude-opus-4-5-20251101:output_tokens': 2500,
|
||||
|
||||
// Claude Haiku 4.5
|
||||
'claude:claude-haiku-4-5-20251001:input_tokens': 100,
|
||||
'claude:claude-haiku-4-5-20251001:ephemeral_5m_input_tokens': 100 * 1.25,
|
||||
'claude:claude-haiku-4-5-20251001:ephemeral_1h_input_tokens': 100 * 2,
|
||||
'claude:claude-haiku-4-5-20251001:cache_read_input_tokens': 100 * 0.1,
|
||||
'claude:claude-haiku-4-5-20251001:output_tokens': 500,
|
||||
|
||||
// Claude Sonnet 4.5
|
||||
'claude:claude-sonnet-4-5-20250929:input_tokens': 300,
|
||||
'claude:claude-sonnet-4-5-20250929:ephemeral_5m_input_tokens': 300 * 1.25,
|
||||
|
||||
Reference in New Issue
Block a user