77
88import { CCS_CONTROL_PANEL_SECRET , CLIPROXY_DEFAULT_PORT } from './config-generator' ;
99
10+ /** Per-account usage statistics */
11+ export interface AccountUsageStats {
12+ /** Account email or identifier */
13+ source : string ;
14+ /** Number of successful requests */
15+ successCount : number ;
16+ /** Number of failed requests */
17+ failureCount : number ;
18+ /** Total tokens used */
19+ totalTokens : number ;
20+ /** Last request timestamp */
21+ lastUsedAt ?: string ;
22+ }
23+
1024/** Usage statistics from CLIProxyAPI */
1125export interface CliproxyStats {
1226 /** Total number of requests processed */
1327 totalRequests : number ;
28+ /** Total successful requests */
29+ successCount : number ;
30+ /** Total failed requests */
31+ failureCount : number ;
1432 /** Token counts */
1533 tokens : {
1634 input : number ;
@@ -21,6 +39,8 @@ export interface CliproxyStats {
2139 requestsByModel : Record < string , number > ;
2240 /** Requests grouped by provider */
2341 requestsByProvider : Record < string , number > ;
42+ /** Per-account usage breakdown */
43+ accountStats : Record < string , AccountUsageStats > ;
2444 /** Number of quota exceeded (429) events */
2545 quotaExceededCount : number ;
2646 /** Number of request retries */
@@ -29,6 +49,21 @@ export interface CliproxyStats {
2949 collectedAt : string ;
3050}
3151
52+ /** Request detail from CLIProxyAPI */
53+ interface RequestDetail {
54+ timestamp : string ;
55+ source : string ;
56+ auth_index : number ;
57+ tokens : {
58+ input_tokens : number ;
59+ output_tokens : number ;
60+ reasoning_tokens : number ;
61+ cached_tokens : number ;
62+ total_tokens : number ;
63+ } ;
64+ failed : boolean ;
65+ }
66+
3267/** Usage API response from CLIProxyAPI /v0/management/usage endpoint */
3368interface UsageApiResponse {
3469 failed_requests ?: number ;
@@ -47,6 +82,7 @@ interface UsageApiResponse {
4782 {
4883 total_requests ?: number ;
4984 total_tokens ?: number ;
85+ details ?: RequestDetail [ ] ;
5086 }
5187 > ;
5288 }
@@ -83,16 +119,55 @@ export async function fetchCliproxyStats(
83119 const data = ( await response . json ( ) ) as UsageApiResponse ;
84120 const usage = data . usage ;
85121
86- // Extract models and providers from the nested API structure
122+ // Extract models, providers, and per-account stats from the nested API structure
87123 const requestsByModel : Record < string , number > = { } ;
88124 const requestsByProvider : Record < string , number > = { } ;
125+ const accountStats : Record < string , AccountUsageStats > = { } ;
126+ let totalSuccessCount = 0 ;
127+ let totalFailureCount = 0 ;
128+ let totalInputTokens = 0 ;
129+ let totalOutputTokens = 0 ;
89130
90131 if ( usage ?. apis ) {
91132 for ( const [ provider , providerData ] of Object . entries ( usage . apis ) ) {
92133 requestsByProvider [ provider ] = providerData . total_requests ?? 0 ;
93134 if ( providerData . models ) {
94135 for ( const [ model , modelData ] of Object . entries ( providerData . models ) ) {
95136 requestsByModel [ model ] = modelData . total_requests ?? 0 ;
137+
138+ // Aggregate per-account stats from request details
139+ if ( modelData . details ) {
140+ for ( const detail of modelData . details ) {
141+ const source = detail . source || 'unknown' ;
142+
143+ // Initialize account stats if not exists
144+ if ( ! accountStats [ source ] ) {
145+ accountStats [ source ] = {
146+ source,
147+ successCount : 0 ,
148+ failureCount : 0 ,
149+ totalTokens : 0 ,
150+ } ;
151+ }
152+
153+ // Update account stats
154+ if ( detail . failed ) {
155+ accountStats [ source ] . failureCount ++ ;
156+ totalFailureCount ++ ;
157+ } else {
158+ accountStats [ source ] . successCount ++ ;
159+ totalSuccessCount ++ ;
160+ }
161+
162+ const tokens = detail . tokens ?. total_tokens ?? 0 ;
163+ accountStats [ source ] . totalTokens += tokens ;
164+ accountStats [ source ] . lastUsedAt = detail . timestamp ;
165+
166+ // Aggregate token breakdowns
167+ totalInputTokens += detail . tokens ?. input_tokens ?? 0 ;
168+ totalOutputTokens += detail . tokens ?. output_tokens ?? 0 ;
169+ }
170+ }
96171 }
97172 }
98173 }
@@ -101,13 +176,16 @@ export async function fetchCliproxyStats(
101176 // Normalize the response to our interface
102177 return {
103178 totalRequests : usage ?. total_requests ?? 0 ,
179+ successCount : totalSuccessCount ,
180+ failureCount : totalFailureCount ,
104181 tokens : {
105- input : 0 , // API doesn't provide input/output breakdown
106- output : 0 ,
182+ input : totalInputTokens ,
183+ output : totalOutputTokens ,
107184 total : usage ?. total_tokens ?? 0 ,
108185 } ,
109186 requestsByModel,
110187 requestsByProvider,
188+ accountStats,
111189 quotaExceededCount : usage ?. failure_count ?? data . failed_requests ?? 0 ,
112190 retryCount : 0 , // API doesn't track retries separately
113191 collectedAt : new Date ( ) . toISOString ( ) ,
0 commit comments