@@ -35,6 +35,22 @@ export interface UsageMeta {
3535let cache : Record < string , DayUsage > | null = null ;
3636let saveTimer : ReturnType < typeof setTimeout > | null = null ;
3737
38+ function tokenCount ( v : unknown ) : number {
39+ const n = typeof v === 'number' || typeof v === 'string' ? Number ( v ) : 0 ;
40+ return Number . isFinite ( n ) && n >= 0 ? n : 0 ;
41+ }
42+
43+ function ownUsage ( map : Record < string , DimUsage > , key : string ) : DimUsage {
44+ if ( Object . prototype . hasOwnProperty . call ( map , key ) ) return map [ key ] ;
45+ const usage = { in : 0 , out : 0 } ;
46+ Object . defineProperty ( map , key , { value : usage , enumerable : true , configurable : true , writable : true } ) ;
47+ return usage ;
48+ }
49+
50+ function setOwnLabel ( map : Record < string , string > , key : string , label : string ) {
51+ Object . defineProperty ( map , key , { value : label , enumerable : true , configurable : true , writable : true } ) ;
52+ }
53+
3854export function dayKey ( d : Date ) : string {
3955 const m = `${ d . getMonth ( ) + 1 } ` . padStart ( 2 , '0' ) ;
4056 const day = `${ d . getDate ( ) } ` . padStart ( 2 , '0' ) ;
@@ -44,9 +60,17 @@ export function dayKey(d: Date): string {
4460function readDim ( v : unknown ) : Record < string , DimUsage > | undefined {
4561 if ( ! v || typeof v !== 'object' ) return undefined ;
4662 const out : Record < string , DimUsage > = { } ;
47- for ( const [ k , e ] of Object . entries ( v as Record < string , Partial < DimUsage > | null > ) )
48- out [ k ] = { in : Number ( e ?. in ) || 0 , out : Number ( e ?. out ) || 0 } ;
49- return out ;
63+ for ( const [ rawKey , e ] of Object . entries ( v as Record < string , Partial < DimUsage > | null > ) ) {
64+ const key = rawKey . trim ( ) ;
65+ if ( ! key ) continue ;
66+ const inTokens = tokenCount ( e ?. in ) ;
67+ const outTokens = tokenCount ( e ?. out ) ;
68+ if ( ! inTokens && ! outTokens ) continue ;
69+ const usage = ownUsage ( out , key ) ;
70+ usage . in += inTokens ;
71+ usage . out += outTokens ;
72+ }
73+ return Object . keys ( out ) . length ? out : undefined ;
5074}
5175
5276function load ( ) : Record < string , DayUsage > {
@@ -59,17 +83,21 @@ function load(): Record<string, DayUsage> {
5983 for ( const [ k , v ] of Object . entries ( parsed ) ) {
6084 const d = v as Partial < DayUsage > | null ;
6185 if ( ! / ^ \d { 4 } - \d { 2 } - \d { 2 } $ / . test ( k ) ) continue ;
62- const day : DayUsage = { in : Number ( d ?. in ) || 0 , out : Number ( d ?. out ) || 0 } ;
86+ const day : DayUsage = { in : tokenCount ( d ?. in ) , out : tokenCount ( d ?. out ) } ;
6387 const prov = readDim ( d ?. prov ) ;
6488 if ( prov ) day . prov = prov ;
6589 const models = readDim ( d ?. models ) ;
6690 if ( models ) day . models = models ;
6791 const agents = readDim ( d ?. agents ) ;
6892 if ( agents ) day . agents = agents ;
6993 if ( d ?. agentLabels && typeof d . agentLabels === 'object' ) {
70- day . agentLabels = { } ;
71- for ( const [ ak , al ] of Object . entries ( d . agentLabels ) )
72- if ( typeof al === 'string' && al ) day . agentLabels [ ak ] = al ;
94+ const labels : Record < string , string > = { } ;
95+ for ( const [ rawKey , rawLabel ] of Object . entries ( d . agentLabels ) ) {
96+ const key = rawKey . trim ( ) ;
97+ const label = typeof rawLabel === 'string' ? rawLabel . trim ( ) : '' ;
98+ if ( key && label ) setOwnLabel ( labels , key , label ) ;
99+ }
100+ if ( Object . keys ( labels ) . length ) day . agentLabels = labels ;
73101 }
74102 cache [ k ] = day ;
75103 }
@@ -98,24 +126,26 @@ function persist() {
98126/** 空白/缺失的 key 归入 'other' 桶。 */
99127function bump ( map : Record < string , DimUsage > , key : string | undefined , inT : number , outT : number ) : string {
100128 const k = key ?. trim ( ) || 'other' ;
101- const e = ( map [ k ] ??= { in : 0 , out : 0 } ) ;
129+ const e = ownUsage ( map , k ) ;
102130 e . in += inT ;
103131 e . out += outT ;
104132 return k ;
105133}
106134
107135export function recordUsage ( inTokens : number , outTokens : number , meta ?: UsageMeta ) {
108- if ( ! inTokens && ! outTokens ) return ;
136+ const inT = tokenCount ( inTokens ) ;
137+ const outT = tokenCount ( outTokens ) ;
138+ if ( ! inT && ! outT ) return ;
109139 const map = load ( ) ;
110140 const k = dayKey ( new Date ( ) ) ;
111141 const d = ( map [ k ] ??= { in : 0 , out : 0 } ) ;
112- d . in += inTokens ;
113- d . out += outTokens ;
114- bump ( ( d . prov ??= { } ) , meta ?. provider , inTokens , outTokens ) ;
115- bump ( ( d . models ??= { } ) , meta ?. model , inTokens , outTokens ) ;
116- const agentKey = bump ( ( d . agents ??= { } ) , meta ?. agent , inTokens , outTokens ) ;
142+ d . in += inT ;
143+ d . out += outT ;
144+ bump ( ( d . prov ??= { } ) , meta ?. provider , inT , outT ) ;
145+ bump ( ( d . models ??= { } ) , meta ?. model , inT , outT ) ;
146+ const agentKey = bump ( ( d . agents ??= { } ) , meta ?. agent , inT , outT ) ;
117147 const label = meta ?. agentLabel ?. trim ( ) ;
118- if ( label && agentKey !== 'other' ) ( d . agentLabels ??= { } ) [ agentKey ] = label ;
148+ if ( label && agentKey !== 'other' ) setOwnLabel ( ( d . agentLabels ??= { } ) , agentKey , label ) ;
119149 persist ( ) ;
120150}
121151
@@ -130,7 +160,7 @@ export function sumDimension(days: DayUsage[], dim: UsageDimension): [string, Di
130160 const m = d [ dim ] ;
131161 if ( ! m ) continue ;
132162 for ( const [ k , v ] of Object . entries ( m ) ) {
133- const e = ( acc [ k ] ??= { in : 0 , out : 0 } ) ;
163+ const e = ownUsage ( acc , k ) ;
134164 e . in += v . in ;
135165 e . out += v . out ;
136166 }
@@ -141,7 +171,10 @@ export function sumDimension(days: DayUsage[], dim: UsageDimension): [string, Di
141171/** 汇总各天记录到的 agent 展示名(后出现的覆盖先出现的)。 */
142172export function collectAgentLabels ( days : DayUsage [ ] ) : Record < string , string > {
143173 const out : Record < string , string > = { } ;
144- for ( const d of days ) if ( d . agentLabels ) Object . assign ( out , d . agentLabels ) ;
174+ for ( const d of days ) {
175+ if ( ! d . agentLabels ) continue ;
176+ for ( const [ key , label ] of Object . entries ( d . agentLabels ) ) setOwnLabel ( out , key , label ) ;
177+ }
145178 return out ;
146179}
147180
0 commit comments