@@ -101,5 +101,111 @@ describe('buildAgentsData', () => {
101101 // sorted by weekly_spent desc
102102 expect ( out [ 0 ] . weekly_spent ! >= out [ 1 ] . weekly_spent ! ) . toBe ( true )
103103 } )
104- } )
105104
105+ it ( 'handles missing metrics gracefully and normalizes defaults' , ( ) => {
106+ const agents = [
107+ {
108+ id : 'solo' ,
109+ version : '0.1.0' ,
110+ data : { description : 'no name provided' } ,
111+ created_at : new Date ( '2025-02-01T00:00:00.000Z' ) ,
112+ publisher : { id : 'codebuff' , name : 'Codebuff' , verified : true , avatar_url : null } ,
113+ } ,
114+ ] as any
115+
116+ const out = buildAgentsData ( {
117+ agents,
118+ usageMetrics : [ ] ,
119+ weeklyMetrics : [ ] ,
120+ perVersionMetrics : [ ] ,
121+ perVersionWeeklyMetrics : [ ] ,
122+ } )
123+
124+ expect ( out ) . toHaveLength ( 1 )
125+ const a = out [ 0 ]
126+ // falls back to id when name missing
127+ expect ( a . name ) . toBe ( 'solo' )
128+ // defaults present
129+ expect ( a . weekly_spent ) . toBe ( 0 )
130+ expect ( a . weekly_runs ) . toBe ( 0 )
131+ expect ( a . total_spent ) . toBe ( 0 )
132+ expect ( a . usage_count ) . toBe ( 0 )
133+ expect ( a . avg_cost_per_invocation ) . toBe ( 0 )
134+ expect ( a . unique_users ) . toBe ( 0 )
135+ expect ( a . last_used ) . toBeUndefined ( )
136+ expect ( a . version_stats ) . toEqual ( { } )
137+ expect ( a . tags ) . toEqual ( [ ] )
138+ // created_at normalized to string
139+ expect ( typeof a . created_at ) . toBe ( 'string' )
140+ } )
141+
142+ it ( 'uses data.name for aggregate metrics and agent.id for version stats' , ( ) => {
143+ const agents = [
144+ {
145+ id : 'file-picker' ,
146+ version : '1.2.0' ,
147+ data : { name : 'File Picker' } ,
148+ created_at : '2025-03-01T00:00:00.000Z' ,
149+ publisher : { id : 'codebuff' , name : 'Codebuff' , verified : true , avatar_url : null } ,
150+ } ,
151+ ] as any
152+
153+ // Aggregate metrics keyed by data.name
154+ const usageMetrics = [
155+ {
156+ publisher_id : 'codebuff' ,
157+ agent_name : 'File Picker' ,
158+ total_invocations : 7 ,
159+ total_dollars : 3.5 ,
160+ avg_cost_per_run : 0.5 ,
161+ unique_users : 2 ,
162+ last_used : new Date ( '2025-03-02T00:00:00.000Z' ) ,
163+ } ,
164+ ]
165+ const weeklyMetrics = [
166+ { publisher_id : 'codebuff' , agent_name : 'File Picker' , weekly_runs : 4 , weekly_dollars : 1.5 } ,
167+ ]
168+
169+ // Version stats keyed by agent.id in runs
170+ const perVersionMetrics = [
171+ {
172+ publisher_id : 'codebuff' ,
173+ agent_name : 'file-picker' ,
174+ agent_version : '1.2.0' ,
175+ total_invocations : 4 ,
176+ total_dollars : 2 ,
177+ avg_cost_per_run : 0.5 ,
178+ unique_users : 2 ,
179+ last_used : new Date ( '2025-03-02T00:00:00.000Z' ) ,
180+ } ,
181+ ]
182+ const perVersionWeeklyMetrics = [
183+ {
184+ publisher_id : 'codebuff' ,
185+ agent_name : 'file-picker' ,
186+ agent_version : '1.2.0' ,
187+ weekly_runs : 2 ,
188+ weekly_dollars : 1 ,
189+ } ,
190+ ]
191+
192+ const out = buildAgentsData ( {
193+ agents : agents as any ,
194+ usageMetrics : usageMetrics as any ,
195+ weeklyMetrics : weeklyMetrics as any ,
196+ perVersionMetrics : perVersionMetrics as any ,
197+ perVersionWeeklyMetrics : perVersionWeeklyMetrics as any ,
198+ } )
199+
200+ expect ( out ) . toHaveLength ( 1 )
201+ const fp = out [ 0 ]
202+ // Aggregate metrics align with data.name
203+ expect ( fp . name ) . toBe ( 'File Picker' )
204+ expect ( fp . weekly_runs ) . toBe ( 4 )
205+ expect ( fp . weekly_spent ) . toBe ( 1.5 )
206+ expect ( fp . usage_count ) . toBe ( 7 )
207+ expect ( fp . total_spent ) . toBe ( 3.5 )
208+ // Version stats keyed by id@version (not display name)
209+ expect ( fp . version_stats ?. [ '1.2.0' ] ) . toMatchObject ( { weekly_runs : 2 , weekly_dollars : 1 } )
210+ } )
211+ } )
0 commit comments