77 type AutoRoutingClassifierAnalyticsResponse ,
88 type AutoRoutingClassifierModelResponse ,
99} from '@kilocode/auto-routing-contracts' ;
10- import { useEffect , useMemo , useState , type ReactNode } from 'react' ;
10+ import React , { useEffect , useMemo , useState , type ReactNode } from 'react' ;
1111import { useMutation , useQuery , useQueryClient } from '@tanstack/react-query' ;
1212import { toast } from 'sonner' ;
1313import { BarChart3 , Clock3 , DollarSign , HelpCircle , RefreshCw , Route , Save } from 'lucide-react' ;
@@ -31,6 +31,7 @@ import {
3131 type OpenRouterModelsResponse ,
3232} from '@/lib/organizations/organization-types' ;
3333import { cn } from '@/lib/utils' ;
34+ import { formatBodySizeKilobytes } from './auto-routing-format' ;
3435
3536const periods : Array < { value : AutoRoutingAnalyticsPeriod ; label : string } > = [
3637 { value : '1h' , label : '1h' } ,
@@ -208,150 +209,156 @@ function EmptyTableRow({ colSpan }: { colSpan: number }) {
208209 ) ;
209210}
210211
211- function BreakdownTables ( {
212+ export function AutoRoutingBreakdownTables ( {
212213 analytics,
213214 loading,
214215} : {
215216 analytics ?: AutoRoutingClassifierAnalyticsResponse ;
216217 loading : boolean ;
217218} ) {
218219 return (
219- < div className = "grid gap-4 xl:grid-cols-4" >
220- < BreakdownCard
221- title = "Status"
222- help = "Breakdown by raw classifier status, including classifier_error:<subtype> rows for classifier failures."
223- loading = { loading }
224- >
225- < Table >
226- < TableHeader >
227- < TableRow >
228- < TableHead > Status</ TableHead >
229- < TableHead className = "text-right" > Requests</ TableHead >
230- </ TableRow >
231- </ TableHeader >
232- < TableBody >
233- { analytics ?. statusBreakdown . length ? (
234- analytics . statusBreakdown . map ( row => (
235- < TableRow key = { row . status } >
236- < TableCell >
237- < Badge variant = "outline" className = "max-w-56 truncate" >
238- { row . status || 'unknown' }
239- </ Badge >
240- </ TableCell >
241- < TableCell className = "text-right tabular-nums" >
242- { formatNumber ( row . requests ) }
243- </ TableCell >
244- </ TableRow >
245- ) )
246- ) : (
247- < EmptyTableRow colSpan = { 2 } />
248- ) }
249- </ TableBody >
250- </ Table >
251- </ BreakdownCard >
252-
253- < BreakdownCard
254- title = "Task Types"
255- help = "Successful classifier task categories and their average classifier confidence."
256- loading = { loading }
257- >
258- < Table >
259- < TableHeader >
260- < TableRow >
261- < TableHead > Task</ TableHead >
262- < TableHead className = "text-right" > Requests</ TableHead >
263- < TableHead className = "text-right" > Confidence</ TableHead >
264- </ TableRow >
265- </ TableHeader >
266- < TableBody >
267- { analytics ?. taskTypeBreakdown . length ? (
268- analytics . taskTypeBreakdown . map ( row => (
269- < TableRow key = { row . taskType } >
270- < TableCell className = "capitalize" > { row . taskType . replaceAll ( '_' , ' ' ) } </ TableCell >
271- < TableCell className = "text-right tabular-nums" >
272- { formatNumber ( row . requests ) }
273- </ TableCell >
274- < TableCell className = "text-right tabular-nums" >
275- { formatPercent ( row . avgConfidence ) }
276- </ TableCell >
277- </ TableRow >
278- ) )
279- ) : (
280- < EmptyTableRow colSpan = { 3 } />
281- ) }
282- </ TableBody >
283- </ Table >
284- </ BreakdownCard >
285-
286- < BreakdownCard
287- title = "Task Subtypes"
288- help = "Successful classifier task and subtask pairs with their average classifier confidence."
289- loading = { loading }
290- >
291- < Table >
292- < TableHeader >
293- < TableRow >
294- < TableHead > Type</ TableHead >
295- < TableHead > Subtype</ TableHead >
296- < TableHead className = "text-right" > Requests</ TableHead >
297- < TableHead className = "text-right" > Confidence</ TableHead >
298- </ TableRow >
299- </ TableHeader >
300- < TableBody >
301- { analytics ?. taskSubtypeBreakdown . length ? (
302- analytics . taskSubtypeBreakdown . map ( row => (
303- < TableRow key = { `${ row . taskType } :${ row . subtaskType } ` } >
304- < TableCell className = "max-w-32 truncate capitalize" >
305- { row . taskType . replaceAll ( '_' , ' ' ) }
306- </ TableCell >
307- < TableCell className = "max-w-40 truncate capitalize" >
308- { row . subtaskType . replaceAll ( '_' , ' ' ) }
309- </ TableCell >
310- < TableCell className = "text-right tabular-nums" >
311- { formatNumber ( row . requests ) }
312- </ TableCell >
313- < TableCell className = "text-right tabular-nums" >
314- { formatPercent ( row . avgConfidence ) }
315- </ TableCell >
316- </ TableRow >
317- ) )
318- ) : (
319- < EmptyTableRow colSpan = { 4 } />
320- ) }
321- </ TableBody >
322- </ Table >
323- </ BreakdownCard >
324-
325- < BreakdownCard
326- title = "Classifier Models"
327- help = "Classifier model used for each request, or unknown when no classifier call happened."
328- loading = { loading }
329- >
330- < Table >
331- < TableHeader >
332- < TableRow >
333- < TableHead > Model</ TableHead >
334- < TableHead className = "text-right" > Requests</ TableHead >
335- </ TableRow >
336- </ TableHeader >
337- < TableBody >
338- { analytics ?. classifierModelBreakdown . length ? (
339- analytics . classifierModelBreakdown . map ( row => (
340- < TableRow key = { row . classifierModel } >
341- < TableCell className = "max-w-64 truncate font-mono text-xs" >
342- { row . classifierModel || 'unknown' }
343- </ TableCell >
344- < TableCell className = "text-right tabular-nums" >
345- { formatNumber ( row . requests ) }
346- </ TableCell >
347- </ TableRow >
348- ) )
349- ) : (
350- < EmptyTableRow colSpan = { 2 } />
351- ) }
352- </ TableBody >
353- </ Table >
354- </ BreakdownCard >
220+ < div className = "flex flex-col gap-4" >
221+ < div className = "grid gap-4 xl:grid-cols-2" >
222+ < BreakdownCard
223+ title = "Status"
224+ help = "Breakdown by raw classifier status, including classifier_error:<subtype> rows for classifier failures."
225+ loading = { loading }
226+ >
227+ < Table >
228+ < TableHeader >
229+ < TableRow >
230+ < TableHead > Status</ TableHead >
231+ < TableHead className = "text-right" > Requests</ TableHead >
232+ </ TableRow >
233+ </ TableHeader >
234+ < TableBody >
235+ { analytics ?. statusBreakdown . length ? (
236+ analytics . statusBreakdown . map ( row => (
237+ < TableRow key = { row . status } >
238+ < TableCell >
239+ < Badge variant = "outline" className = "max-w-56 truncate" >
240+ { row . status || 'unknown' }
241+ </ Badge >
242+ </ TableCell >
243+ < TableCell className = "text-right tabular-nums" >
244+ { formatNumber ( row . requests ) }
245+ </ TableCell >
246+ </ TableRow >
247+ ) )
248+ ) : (
249+ < EmptyTableRow colSpan = { 2 } />
250+ ) }
251+ </ TableBody >
252+ </ Table >
253+ </ BreakdownCard >
254+
255+ < BreakdownCard
256+ title = "Classifier Models"
257+ help = "Classifier model used for each request, or unknown when no classifier call happened."
258+ loading = { loading }
259+ >
260+ < Table >
261+ < TableHeader >
262+ < TableRow >
263+ < TableHead > Model</ TableHead >
264+ < TableHead className = "text-right" > Requests</ TableHead >
265+ </ TableRow >
266+ </ TableHeader >
267+ < TableBody >
268+ { analytics ?. classifierModelBreakdown . length ? (
269+ analytics . classifierModelBreakdown . map ( row => (
270+ < TableRow key = { row . classifierModel } >
271+ < TableCell className = "max-w-64 truncate font-mono text-xs" >
272+ { row . classifierModel || 'unknown' }
273+ </ TableCell >
274+ < TableCell className = "text-right tabular-nums" >
275+ { formatNumber ( row . requests ) }
276+ </ TableCell >
277+ </ TableRow >
278+ ) )
279+ ) : (
280+ < EmptyTableRow colSpan = { 2 } />
281+ ) }
282+ </ TableBody >
283+ </ Table >
284+ </ BreakdownCard >
285+ </ div >
286+
287+ < div className = "grid gap-4 xl:grid-cols-2" >
288+ < BreakdownCard
289+ title = "Task Types"
290+ help = "Successful classifier task categories and their average classifier confidence."
291+ loading = { loading }
292+ >
293+ < Table >
294+ < TableHeader >
295+ < TableRow >
296+ < TableHead > Task</ TableHead >
297+ < TableHead className = "text-right" > Requests</ TableHead >
298+ < TableHead className = "text-right" > Confidence</ TableHead >
299+ </ TableRow >
300+ </ TableHeader >
301+ < TableBody >
302+ { analytics ?. taskTypeBreakdown . length ? (
303+ analytics . taskTypeBreakdown . map ( row => (
304+ < TableRow key = { row . taskType } >
305+ < TableCell className = "capitalize" >
306+ { row . taskType . replaceAll ( '_' , ' ' ) }
307+ </ TableCell >
308+ < TableCell className = "text-right tabular-nums" >
309+ { formatNumber ( row . requests ) }
310+ </ TableCell >
311+ < TableCell className = "text-right tabular-nums" >
312+ { formatPercent ( row . avgConfidence ) }
313+ </ TableCell >
314+ </ TableRow >
315+ ) )
316+ ) : (
317+ < EmptyTableRow colSpan = { 3 } />
318+ ) }
319+ </ TableBody >
320+ </ Table >
321+ </ BreakdownCard >
322+
323+ < BreakdownCard
324+ title = "Task Subtypes"
325+ help = "Successful classifier task and subtask pairs with their average classifier confidence."
326+ loading = { loading }
327+ >
328+ < Table >
329+ < TableHeader >
330+ < TableRow >
331+ < TableHead > Type</ TableHead >
332+ < TableHead > Subtype</ TableHead >
333+ < TableHead className = "text-right" > Requests</ TableHead >
334+ < TableHead className = "text-right" > Confidence</ TableHead >
335+ </ TableRow >
336+ </ TableHeader >
337+ < TableBody >
338+ { analytics ?. taskSubtypeBreakdown . length ? (
339+ analytics . taskSubtypeBreakdown . map ( row => (
340+ < TableRow key = { `${ row . taskType } :${ row . subtaskType } ` } >
341+ < TableCell className = "max-w-32 truncate capitalize" >
342+ { row . taskType . replaceAll ( '_' , ' ' ) }
343+ </ TableCell >
344+ < TableCell className = "max-w-40 truncate capitalize" >
345+ { row . subtaskType . replaceAll ( '_' , ' ' ) }
346+ </ TableCell >
347+ < TableCell className = "text-right tabular-nums" >
348+ { formatNumber ( row . requests ) }
349+ </ TableCell >
350+ < TableCell className = "text-right tabular-nums" >
351+ { formatPercent ( row . avgConfidence ) }
352+ </ TableCell >
353+ </ TableRow >
354+ ) )
355+ ) : (
356+ < EmptyTableRow colSpan = { 4 } />
357+ ) }
358+ </ TableBody >
359+ </ Table >
360+ </ BreakdownCard >
361+ </ div >
355362 </ div >
356363 ) ;
357364}
@@ -576,15 +583,18 @@ export function AutoRoutingAdminContent() {
576583 />
577584 < MetricCard
578585 title = "Body Size"
579- value = { ` ${ formatDecimal ( summary ?. avgBodyBytes ?? 0 ) } B` }
586+ value = { formatBodySizeKilobytes ( summary ?. avgBodyBytes ?? 0 ) }
580587 detail = { `${ formatPercent ( summary ?. avgConfidence ?? 0 ) } avg confidence` }
581588 icon = { BarChart3 }
582589 loading = { analyticsQuery . isLoading }
583- help = "Average mirrored body size in bytes . The detail shows average classifier confidence for successful classifications."
590+ help = "Average mirrored body size in KB . The detail shows average classifier confidence for successful classifications."
584591 />
585592 </ div >
586593
587- < BreakdownTables analytics = { analyticsQuery . data } loading = { analyticsQuery . isLoading } />
594+ < AutoRoutingBreakdownTables
595+ analytics = { analyticsQuery . data }
596+ loading = { analyticsQuery . isLoading }
597+ />
588598 </ >
589599 ) }
590600 </ div >
0 commit comments