mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 00:19:42 +02:00
feat: persistent token tracking with global stats aggregation
- Add restoreTokens() method to Session class for recovery after restart - Add GlobalStats type for cumulative usage tracking across all sessions - Accumulate tokens from deleted sessions into global stats - Track lifetime session count with incrementSessionsCreated() - Add /api/stats endpoint for global stats - Include globalStats in /api/status response - Frontend shows aggregate tokens + cost in header - Fix respawn controller config to filter undefined values - Add 7 new tests for global stats functionality (v0.1343) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+65
-1
@@ -17,7 +17,7 @@
|
||||
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
||||
import { homedir } from 'node:os';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { AppState, createInitialState, RalphSessionState, createInitialRalphSessionState } from './types.js';
|
||||
import { AppState, createInitialState, RalphSessionState, createInitialRalphSessionState, GlobalStats, createInitialGlobalStats } from './types.js';
|
||||
|
||||
/** Debounce delay for batching state writes (ms) */
|
||||
const SAVE_DEBOUNCE_MS = 500;
|
||||
@@ -208,6 +208,70 @@ export class StateStore {
|
||||
this.saveRalphStatesNow();
|
||||
}
|
||||
|
||||
// ========== Global Stats Methods ==========
|
||||
|
||||
/** Returns global stats, creating initial stats if needed. */
|
||||
getGlobalStats(): GlobalStats {
|
||||
if (!this.state.globalStats) {
|
||||
this.state.globalStats = createInitialGlobalStats();
|
||||
}
|
||||
return this.state.globalStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tokens and cost to global stats.
|
||||
* Call when a session is deleted to preserve its usage in lifetime stats.
|
||||
*/
|
||||
addToGlobalStats(inputTokens: number, outputTokens: number, cost: number): void {
|
||||
const stats = this.getGlobalStats();
|
||||
stats.totalInputTokens += inputTokens;
|
||||
stats.totalOutputTokens += outputTokens;
|
||||
stats.totalCost += cost;
|
||||
stats.lastUpdatedAt = Date.now();
|
||||
this.save();
|
||||
}
|
||||
|
||||
/** Increments the total sessions created counter. */
|
||||
incrementSessionsCreated(): void {
|
||||
const stats = this.getGlobalStats();
|
||||
stats.totalSessionsCreated += 1;
|
||||
stats.lastUpdatedAt = Date.now();
|
||||
this.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns aggregate stats combining global (deleted sessions) + active sessions.
|
||||
* @param activeSessions Map of active session states
|
||||
*/
|
||||
getAggregateStats(activeSessions: Record<string, { inputTokens?: number; outputTokens?: number; totalCost?: number }>): {
|
||||
totalInputTokens: number;
|
||||
totalOutputTokens: number;
|
||||
totalCost: number;
|
||||
totalSessionsCreated: number;
|
||||
activeSessionsCount: number;
|
||||
} {
|
||||
const global = this.getGlobalStats();
|
||||
let activeInput = 0;
|
||||
let activeOutput = 0;
|
||||
let activeCost = 0;
|
||||
let activeCount = 0;
|
||||
|
||||
for (const session of Object.values(activeSessions)) {
|
||||
activeInput += session.inputTokens ?? 0;
|
||||
activeOutput += session.outputTokens ?? 0;
|
||||
activeCost += session.totalCost ?? 0;
|
||||
activeCount++;
|
||||
}
|
||||
|
||||
return {
|
||||
totalInputTokens: global.totalInputTokens + activeInput,
|
||||
totalOutputTokens: global.totalOutputTokens + activeOutput,
|
||||
totalCost: global.totalCost + activeCost,
|
||||
totalSessionsCreated: global.totalSessionsCreated,
|
||||
activeSessionsCount: activeCount,
|
||||
};
|
||||
}
|
||||
|
||||
// ========== Inner State Methods (Ralph Loop tracking) ==========
|
||||
|
||||
private loadRalphStates(): void {
|
||||
|
||||
Reference in New Issue
Block a user