UNPKG

manifest

Version:

Self-hosted Manifest LLM router with embedded server, SQLite database, and dashboard

205 lines 11.6 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AggregationService = void 0; const common_1 = require("@nestjs/common"); const typeorm_1 = require("@nestjs/typeorm"); const typeorm_2 = require("typeorm"); const agent_message_entity_1 = require("../../entities/agent-message.entity"); const range_util_1 = require("../../common/utils/range.util"); const query_helpers_1 = require("./query-helpers"); const tenant_cache_service_1 = require("../../common/services/tenant-cache.service"); const sql_dialect_1 = require("../../common/utils/sql-dialect"); let AggregationService = class AggregationService { turnRepo; dataSource; tenantCache; dialect; constructor(turnRepo, dataSource, tenantCache) { this.turnRepo = turnRepo; this.dataSource = dataSource; this.tenantCache = tenantCache; this.dialect = (0, sql_dialect_1.detectDialect)(this.dataSource.options.type); } async hasAnyData(userId, agentName, tenantId) { const resolved = tenantId ?? (await this.tenantCache.resolve(userId)) ?? undefined; const qb = this.turnRepo.createQueryBuilder('at').select('1').limit(1); (0, query_helpers_1.addTenantFilter)(qb, userId, agentName, resolved); const row = await qb.getRawOne(); return row != null; } async getTokenSummary(range, userId, agentName) { const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined; const interval = (0, range_util_1.rangeToInterval)(range); const prevInterval = (0, range_util_1.rangeToPreviousInterval)(range); const cutoff = (0, sql_dialect_1.computeCutoff)(interval); const prevCutoff = (0, sql_dialect_1.computeCutoff)(prevInterval); const detailQb = this.turnRepo .createQueryBuilder('at') .select('COALESCE(SUM(at.input_tokens), 0)', 'inp') .addSelect('COALESCE(SUM(at.output_tokens), 0)', 'out') .where('at.timestamp >= :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(detailQb, userId, agentName, tenantId); const prevQb = this.turnRepo .createQueryBuilder('at') .select('COALESCE(SUM(at.input_tokens + at.output_tokens), 0)', 'total') .where('at.timestamp >= :prevCutoff', { prevCutoff }) .andWhere('at.timestamp < :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(prevQb, userId, agentName, tenantId); const [detail, prevRow] = await Promise.all([detailQb.getRawOne(), prevQb.getRawOne()]); const inputTotal = Number(detail?.inp ?? 0); const outputTotal = Number(detail?.out ?? 0); const current = inputTotal + outputTotal; const previous = Number(prevRow?.total ?? 0); return { tokens_today: { value: current, trend_pct: (0, query_helpers_1.computeTrend)(current, previous), sub_values: { input: inputTotal, output: outputTotal }, }, input_tokens: inputTotal, output_tokens: outputTotal, }; } async getCostSummary(range, userId, agentName) { const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined; const interval = (0, range_util_1.rangeToInterval)(range); const prevInterval = (0, range_util_1.rangeToPreviousInterval)(range); const cutoff = (0, sql_dialect_1.computeCutoff)(interval); const prevCutoff = (0, sql_dialect_1.computeCutoff)(prevInterval); const safeCost = (0, sql_dialect_1.sqlSanitizeCost)('at.cost_usd'); const currentQb = this.turnRepo .createQueryBuilder('at') .select(`COALESCE(SUM(${safeCost}), 0)`, 'total') .where('at.timestamp >= :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(currentQb, userId, agentName, tenantId); const prevQb = this.turnRepo .createQueryBuilder('at') .select(`COALESCE(SUM(${safeCost}), 0)`, 'total') .where('at.timestamp >= :prevCutoff', { prevCutoff }) .andWhere('at.timestamp < :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(prevQb, userId, agentName, tenantId); const [currentRow, prevRow] = await Promise.all([currentQb.getRawOne(), prevQb.getRawOne()]); const current = Number(currentRow?.total ?? 0); const previous = Number(prevRow?.total ?? 0); return { value: current, trend_pct: (0, query_helpers_1.computeTrend)(current, previous) }; } async getMessageCount(range, userId, agentName) { const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined; const interval = (0, range_util_1.rangeToInterval)(range); const prevInterval = (0, range_util_1.rangeToPreviousInterval)(range); const cutoff = (0, sql_dialect_1.computeCutoff)(interval); const prevCutoff = (0, sql_dialect_1.computeCutoff)(prevInterval); const currentQb = this.turnRepo .createQueryBuilder('at') .select('COUNT(*)', 'total') .where('at.timestamp >= :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(currentQb, userId, agentName, tenantId); const prevQb = this.turnRepo .createQueryBuilder('at') .select('COUNT(*)', 'total') .where('at.timestamp >= :prevCutoff', { prevCutoff }) .andWhere('at.timestamp < :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(prevQb, userId, agentName, tenantId); const [currentRow, prevRow] = await Promise.all([currentQb.getRawOne(), prevQb.getRawOne()]); const current = Number(currentRow?.total ?? 0); const previous = Number(prevRow?.total ?? 0); return { value: current, trend_pct: (0, query_helpers_1.computeTrend)(current, previous) }; } async getPreviousTokenTotal(range, userId, agentName) { const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined; const interval = (0, range_util_1.rangeToInterval)(range); const prevInterval = (0, range_util_1.rangeToPreviousInterval)(range); const cutoff = (0, sql_dialect_1.computeCutoff)(interval); const prevCutoff = (0, sql_dialect_1.computeCutoff)(prevInterval); const prevQb = this.turnRepo .createQueryBuilder('at') .select('COALESCE(SUM(at.input_tokens + at.output_tokens), 0)', 'total') .where('at.timestamp >= :prevCutoff', { prevCutoff }) .andWhere('at.timestamp < :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(prevQb, userId, agentName, tenantId); const row = await prevQb.getRawOne(); return Number(row?.total ?? 0); } async getPreviousCostTotal(range, userId, agentName) { const tenantId = (await this.tenantCache.resolve(userId)) ?? undefined; const interval = (0, range_util_1.rangeToInterval)(range); const prevInterval = (0, range_util_1.rangeToPreviousInterval)(range); const cutoff = (0, sql_dialect_1.computeCutoff)(interval); const prevCutoff = (0, sql_dialect_1.computeCutoff)(prevInterval); const safeCost = (0, sql_dialect_1.sqlSanitizeCost)('at.cost_usd'); const prevQb = this.turnRepo .createQueryBuilder('at') .select(`COALESCE(SUM(${safeCost}), 0)`, 'total') .where('at.timestamp >= :prevCutoff', { prevCutoff }) .andWhere('at.timestamp < :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(prevQb, userId, agentName, tenantId); const row = await prevQb.getRawOne(); return Number(row?.total ?? 0); } async getSummaryMetrics(range, userId, tenantId, agentName) { const interval = (0, range_util_1.rangeToInterval)(range); const prevInterval = (0, range_util_1.rangeToPreviousInterval)(range); const cutoff = (0, sql_dialect_1.computeCutoff)(interval); const prevCutoff = (0, sql_dialect_1.computeCutoff)(prevInterval); const safeCost = (0, sql_dialect_1.sqlSanitizeCost)('at.cost_usd'); const currentQb = this.turnRepo .createQueryBuilder('at') .select('COUNT(*)', 'msg_count') .addSelect('COALESCE(SUM(at.input_tokens), 0)', 'inp') .addSelect('COALESCE(SUM(at.output_tokens), 0)', 'out') .addSelect(`COALESCE(SUM(${safeCost}), 0)`, 'cost') .where('at.timestamp >= :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(currentQb, userId, agentName, tenantId); const prevQb = this.turnRepo .createQueryBuilder('at') .select('COUNT(*)', 'msg_count') .addSelect('COALESCE(SUM(at.input_tokens + at.output_tokens), 0)', 'tokens') .addSelect(`COALESCE(SUM(${safeCost}), 0)`, 'cost') .where('at.timestamp >= :prevCutoff', { prevCutoff }) .andWhere('at.timestamp < :cutoff', { cutoff }); (0, query_helpers_1.addTenantFilter)(prevQb, userId, agentName, tenantId); const [cur, prev] = await Promise.all([currentQb.getRawOne(), prevQb.getRawOne()]); const inputTotal = Number(cur?.inp ?? 0); const outputTotal = Number(cur?.out ?? 0); const curTokens = inputTotal + outputTotal; const prevTokens = Number(prev?.tokens ?? 0); const curCost = Number(cur?.cost ?? 0); const prevCost = Number(prev?.cost ?? 0); const curMsgs = Number(cur?.msg_count ?? 0); const prevMsgs = Number(prev?.msg_count ?? 0); return { tokens: { tokens_today: { value: curTokens, trend_pct: (0, query_helpers_1.computeTrend)(curTokens, prevTokens), sub_values: { input: inputTotal, output: outputTotal }, }, input_tokens: inputTotal, output_tokens: outputTotal, }, cost: { value: curCost, trend_pct: (0, query_helpers_1.computeTrend)(curCost, prevCost) }, messages: { value: curMsgs, trend_pct: (0, query_helpers_1.computeTrend)(curMsgs, prevMsgs) }, }; } }; exports.AggregationService = AggregationService; exports.AggregationService = AggregationService = __decorate([ (0, common_1.Injectable)(), __param(0, (0, typeorm_1.InjectRepository)(agent_message_entity_1.AgentMessage)), __metadata("design:paramtypes", [typeorm_2.Repository, typeorm_2.DataSource, tenant_cache_service_1.TenantCacheService]) ], AggregationService); //# sourceMappingURL=aggregation.service.js.map