@@ -940,11 +940,8 @@ function signalRatesFor(group: Session[], groupToolCalls: ToolCall[]): ModelSign
940940
941941 return {
942942 outputExpansionRate : safeRate ( outputTokens , inputTokens ) ,
943- generationTokenOverhead : safeRate ( outputTokens , inputTokens ) ,
944943 reasoningTokenShare : safeRate ( reasoningOutputTokens , outputTokens ) ,
945944 reasoningOverheadRate : safeRate ( reasoningOutputTokens , Math . max ( 0 , outputTokens - reasoningOutputTokens ) ) ,
946- reasoningTokenOverhead : safeRate ( reasoningOutputTokens , outputTokens ) ,
947- reasoningOutputShare : safeRate ( reasoningOutputTokens , outputTokens ) ,
948945 cacheMissRate : clampRate ( safeRate ( inputTokens - cachedInputTokens , inputTokens ) ) ,
949946 modelThroughputTokensPerSecond : safeRate ( totalTokens , modelDurationSeconds ) ,
950947 modelThroughputOutputTokensPerSecond : safeRate ( outputTokens , modelDurationSeconds ) ,
@@ -995,6 +992,8 @@ function metricSetFromTotals(totals: MetricTotals): ModelSignalMetricSet {
995992 const failurePressure = safeRate ( ( totals . failedModelCalls || 0 ) + totals . failedToolCalls , totals . sessionCount )
996993 const avgModelCallsPerSession = safeRate ( totals . modelCalls , totals . sessionCount )
997994 const outputExpansionRate = safeRate ( totals . outputTokens , totals . inputTokens )
995+ const visibleOutputTokens = Math . max ( 0 , totals . outputTokens - totals . reasoningOutputTokens )
996+ const billableOutputTokens = totals . outputTokens
998997 const reasoningOverheadRate = safeRate ( totals . reasoningOutputTokens , Math . max ( 0 , totals . outputTokens - totals . reasoningOutputTokens ) )
999998 const cacheMissRate = clampRate ( safeRate ( totals . inputTokens - totals . cachedInputTokens , totals . inputTokens ) )
1000999 const modelThroughputOutputTokensPerSecond = safeRate ( totals . outputTokens , modelDurationSeconds )
@@ -1012,6 +1011,8 @@ function metricSetFromTotals(totals: MetricTotals): ModelSignalMetricSet {
10121011 cachedInputTokens : totals . cachedInputTokens ,
10131012 outputTokens : totals . outputTokens ,
10141013 reasoningOutputTokens : totals . reasoningOutputTokens ,
1014+ visibleOutputTokens,
1015+ billableOutputTokens,
10151016 modelDurationMs : totals . modelDurationMs ,
10161017 wallDurationMs,
10171018 activeDurationMs,
@@ -1041,11 +1042,8 @@ function metricSetFromTotals(totals: MetricTotals): ModelSignalMetricSet {
10411042 } ) ,
10421043 avgModelCallsPerSession,
10431044 outputExpansionRate,
1044- generationTokenOverhead : outputExpansionRate ,
10451045 reasoningTokenShare : safeRate ( totals . reasoningOutputTokens , totals . outputTokens ) ,
10461046 reasoningOverheadRate,
1047- reasoningTokenOverhead : safeRate ( totals . reasoningOutputTokens , totals . outputTokens ) ,
1048- reasoningOutputShare : safeRate ( totals . reasoningOutputTokens , totals . outputTokens ) ,
10491047 cacheMissRate,
10501048 modelThroughputTokensPerSecond,
10511049 modelThroughputOutputTokensPerSecond,
@@ -1161,8 +1159,8 @@ function relativeDecrease(current: number, baseline: number): number {
11611159 return ( baseline - current ) / baseline
11621160}
11631161
1164- function reasoningOverhead ( metric : Pick < ModelSignalRates , 'reasoningTokenShare' | ' reasoningOverheadRate' | 'reasoningTokenOverhead' | 'reasoningOutputShare '> ) : number {
1165- return metric . reasoningOverheadRate ?? metric . reasoningTokenOverhead ?? metric . reasoningOutputShare ?? metric . reasoningTokenShare
1162+ function reasoningOverhead ( metric : Pick < ModelSignalRates , 'reasoningOverheadRate' > ) : number {
1163+ return metric . reasoningOverheadRate
11661164}
11671165
11681166function modelSignalDriftFor ( current : ModelSignalMetricSet , baseline : ModelSignalMetricSet ) : ModelSignalDrift {
@@ -1586,13 +1584,11 @@ function anomalySessionsFor(items: Session[], scopedToolCalls: ToolCall[]): Mode
15861584 const reasons : string [ ] = [ ]
15871585 if ( rates . toolFailureRate > 0 ) reasons . push ( 'Tool failure in session' )
15881586 if ( reasoningOverhead ( rates ) >= 0.25 ) reasons . push ( 'High reasoning overhead' )
1589- if ( ( rates . generationTokenOverhead ?? rates . outputExpansionRate ) >= 0.2 ) reasons . push ( 'Generation overhead relative to input' )
1587+ if ( rates . outputExpansionRate >= 0.2 ) reasons . push ( 'Generation overhead relative to input' )
15901588 if ( rates . cacheMissRate >= 0.85 ) reasons . push ( 'Low cache reuse' )
15911589 if ( rates . modelThroughputTokensPerSecond > 0 && rates . modelThroughputTokensPerSecond < 85 ) reasons . push ( 'Low model token throughput' )
15921590 if ( ! reasons . length ) continue
15931591 anomalies . push ( {
1594- session,
1595- id : session . id ,
15961592 sessionId : session . id ,
15971593 sessionKey : session . sessionKey ,
15981594 codexSessionId : session . codexSessionId ,
@@ -1601,22 +1597,25 @@ function anomalySessionsFor(items: Session[], scopedToolCalls: ToolCall[]): Mode
16011597 rawSourcePath : session . rawSourcePath ,
16021598 agentKind : session . agentKind ,
16031599 agentName : session . agentName ,
1604- sourceId : session . sourceId ,
1605- sourceKey : session . sourceKey ,
1606- sourceLabel : session . sourceLabel ,
1607- sourceRootPath : session . sourceRootPath ,
1608- sourceSessionsPath : session . sourceSessionsPath ,
1600+ sourceId : session . sourceId || 0 ,
1601+ sourceKey : session . sourceKey || '' ,
1602+ sourceLabel : session . sourceLabel || session . agentName ,
1603+ sourceRootPath : session . sourceRootPath || '' ,
1604+ sourceSessionsPath : session . sourceSessionsPath || '' ,
16091605 model : session . model ,
1606+ modelCalls : modelCallsForSession ( session ) ,
16101607 totalTokens : session . tokenUsage . totalTokens ,
16111608 inputTokens : session . tokenUsage . inputTokens ,
1609+ cachedInputTokens : session . tokenUsage . cachedInputTokens ,
16121610 outputTokens : session . tokenUsage . outputTokens ,
16131611 reasoningOutputTokens : session . tokenUsage . reasoningOutputTokens ,
1612+ visibleOutputTokens : Math . max ( 0 , session . tokenUsage . outputTokens - session . tokenUsage . reasoningOutputTokens ) ,
1613+ billableOutputTokens : session . tokenUsage . outputTokens ,
16141614 toolCalls : sessionToolCalls . length ,
16151615 failedToolCalls : sessionToolCalls . filter ( ( call ) => ! isSuccessfulToolStatus ( call . status ) ) . length ,
16161616 modelDurationMs : session . modelDurationMs ,
1617- severity : reasons . length > 1 ? 'high' : 'medium' ,
1618- signal : reasons [ 0 ] ,
16191617 reasons,
1618+ score : clampRate ( reasons . length / 5 ) ,
16201619 ...rates
16211620 } )
16221621 }
@@ -1635,6 +1634,8 @@ function modelSignals(filters: UsageScopeFilters = {}): ModelSignals {
16351634 const scopedToolCalls = filteredToolCalls ( { agent : filters . agent , project : filters . project , from : filters . from , to : filters . to } )
16361635 . filter ( ( call ) => sessionIds . has ( call . sessionId ) )
16371636 const rates = signalRatesFor ( scoped , scopedToolCalls )
1637+ const outputTokens = sum ( scoped , ( session ) => session . tokenUsage . outputTokens )
1638+ const reasoningOutputTokens = sum ( scoped , ( session ) => session . tokenUsage . reasoningOutputTokens )
16381639 const cohorts = modelSignalCohortsFor ( scoped , scopedToolCalls )
16391640 return {
16401641 totalSessions : scoped . length ,
@@ -1646,6 +1647,9 @@ function modelSignals(filters: UsageScopeFilters = {}): ModelSignals {
16461647 avgModelCallsPerSession : safeRate ( sum ( scoped , modelCallsForSession ) , scoped . length ) ,
16471648 outputExpansionRate : rates . outputExpansionRate ,
16481649 reasoningTokenShare : rates . reasoningTokenShare ,
1650+ reasoningOverheadRate : rates . reasoningOverheadRate ,
1651+ visibleOutputTokens : Math . max ( 0 , outputTokens - reasoningOutputTokens ) ,
1652+ billableOutputTokens : outputTokens ,
16491653 cacheMissRate : rates . cacheMissRate ,
16501654 modelThroughputTokensPerSecond : rates . modelThroughputTokensPerSecond ,
16511655 modelThroughputOutputTokensPerSecond : rates . modelThroughputOutputTokensPerSecond ,
0 commit comments