From eea27be8eb7874b26a471a8e8672efe9e9bb62ff Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Wed, 8 Oct 2025 18:41:15 -0700 Subject: [PATCH] fix: metering service global write and open ai default model (#1717) --- .../OpenAICompletionService.mjs | 4 ++++ .../puterai/OpenAiCompletionService/index.mjs | 4 ++++ .../MeteringService/MeteringService.ts | 19 +++++++++---------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/backend/src/modules/puterai/OpenAiCompletionService/OpenAICompletionService.mjs b/src/backend/src/modules/puterai/OpenAiCompletionService/OpenAICompletionService.mjs index 96abe3e1..a18e3d26 100644 --- a/src/backend/src/modules/puterai/OpenAiCompletionService/OpenAICompletionService.mjs +++ b/src/backend/src/modules/puterai/OpenAiCompletionService/OpenAICompletionService.mjs @@ -105,6 +105,10 @@ export class OpenAICompletionService { return model_names; } + get_default_model(){ + return this.#defaultModel; + } + async complete({ messages, stream, model, tools, max_tokens, temperature }) { return await this.#complete(messages, { model: model, diff --git a/src/backend/src/modules/puterai/OpenAiCompletionService/index.mjs b/src/backend/src/modules/puterai/OpenAiCompletionService/index.mjs index 15c0e3ad..0452a102 100644 --- a/src/backend/src/modules/puterai/OpenAiCompletionService/index.mjs +++ b/src/backend/src/modules/puterai/OpenAiCompletionService/index.mjs @@ -40,6 +40,10 @@ export class OpenAICompletionServiceWrapper extends BaseService { return await this.openAICompletionService.checkModeration(text); } + get_default_model() { + return this.openAICompletionService.get_default_model(); + } + static IMPLEMENTS = { ['puter-chat-completion']: Object.getOwnPropertyNames(OpenAICompletionService.prototype) .filter(n => n !== 'constructor') diff --git a/src/backend/src/services/abuse-prevention/MeteringService/MeteringService.ts b/src/backend/src/services/abuse-prevention/MeteringService/MeteringService.ts index 83eff0ef..77cc19fd 100644 --- a/src/backend/src/services/abuse-prevention/MeteringService/MeteringService.ts +++ b/src/backend/src/services/abuse-prevention/MeteringService/MeteringService.ts @@ -37,6 +37,7 @@ const POLICY_TYPES = { const GLOBAL_APP_KEY = 'os-global'; // TODO DS: this should be loaded from config or db eventually const METRICS_PREFIX = 'metering'; const POLICY_PREFIX = 'policy'; +const PERIOD_ESCAPE = '_dot_'; // to replace dots in usage types for kvstore paths /** * Handles usage metering and supports stubbs for billing methods for current scoped actor */ @@ -75,6 +76,7 @@ export class MeteringAndBillingService { return this.#superUserService.sudo(async () => { const totalCost = (costOverride ?? COST_MAPS[usageType] * usageAmount) || 0; // TODO DS: apply our policy discounts here eventually + usageType = usageType.replace(/\./g, PERIOD_ESCAPE) as keyof typeof COST_MAPS; // replace dots with underscores for kvstore paths, TODO DS: map this back when reading const appId = actor.type?.app?.uid || GLOBAL_APP_KEY const actorId = actor.type?.user.uuid const pathAndAmountMap = { @@ -96,6 +98,12 @@ export class MeteringAndBillingService { pathAndAmountMap, }) + const puterConsumptionKey = `${METRICS_PREFIX}:puter:${currentMonth}`; // global consumption across all users and apps + this.#kvClientWrapper.incr({ + key: puterConsumptionKey, + pathAndAmountMap + }) + const actorAppUsageKey = `${METRICS_PREFIX}:actor:${actorId}:app:${appId}:${currentMonth}`; this.#kvClientWrapper.incr({ key: actorAppUsageKey, @@ -116,16 +124,7 @@ export class MeteringAndBillingService { [`${appId}.count`]: 1, }, }) - const puterConsumptionKey = `${METRICS_PREFIX}:puter:${currentMonth}`; // global consumption across all users and apps - this.#kvClientWrapper.incr({ - key: puterConsumptionKey, - pathAndAmountMap: { - 'total': totalCost, - [`${usageType}.units`]: usageAmount, - [`${usageType}.cost`]: totalCost, - [`${usageType}.count`]: 1, - } - }) + return (await Promise.all([lastUpdatedPromise, actorUsagesPromise]))[1] as UsageByType; })