@@ -2052,32 +2052,88 @@ fn format_limit_compact_line(
20522052 format ! ( "{label}{pct}{resets}" )
20532053}
20542054
2055- fn format_limits_compact_lines ( l : & crate :: codex_rpc:: AccountRateLimits ) -> ( String , String ) {
2056- let primary_label = l
2057- . primary
2058- . as_ref ( )
2055+ fn format_rolling_limit_lines (
2056+ primary : Option < & crate :: codex_rpc:: RateLimitWindow > ,
2057+ secondary : Option < & crate :: codex_rpc:: RateLimitWindow > ,
2058+ ) -> ( String , String ) {
2059+ let primary_label = primary
20592060 . and_then ( |w| w. window_duration_mins )
20602061 . and_then ( format_window_label)
20612062 . map ( |w| format ! ( "{w} limit:" ) )
20622063 . unwrap_or_else ( || "5h limit:" . to_string ( ) ) ;
2063- let l1 = format_limit_compact_line ( & primary_label, l . primary . as_ref ( ) ) ;
2064- let l2 = format_limit_compact_line ( "Weekly:" , l . secondary . as_ref ( ) ) ;
2064+ let l1 = format_limit_compact_line ( & primary_label, primary) ;
2065+ let l2 = format_limit_compact_line ( "Weekly:" , secondary) ;
20652066 ( l1, l2)
20662067}
20672068
20682069fn format_limits_compact_card_lines (
20692070 l : & crate :: codex_rpc:: AccountRateLimits ,
20702071) -> ( String , Option < String > , Option < String > , Option < String > ) {
2071- let ( primary, secondary) = format_limits_compact_lines ( l) ;
2072- let credits = format_credits_compact_line ( l) . unwrap_or_else ( || "Credits: --" . to_string ( ) ) ;
2072+ let ( rolling_primary, rolling_secondary) = rolling_windows_for_limits ( l) ;
2073+ let ( primary, secondary) = format_rolling_limit_lines ( rolling_primary, rolling_secondary) ;
2074+ if let Some ( ( monthly, used) ) = format_individual_limit_compact_lines ( l) {
2075+ return ( monthly, Some ( used) , Some ( primary) , Some ( secondary) ) ;
2076+ }
20732077
20742078 if let Some ( extra) = format_extra_bucket_compact_line ( l) {
2079+ let credits = format_credits_compact_line ( l) . unwrap_or_else ( || "Credits: --" . to_string ( ) ) ;
20752080 ( primary, Some ( secondary) , Some ( extra) , Some ( credits) )
20762081 } else {
2082+ let credits = format_credits_compact_line ( l) . unwrap_or_else ( || "Credits: --" . to_string ( ) ) ;
20772083 ( primary, Some ( secondary) , Some ( credits) , None )
20782084 }
20792085}
20802086
2087+ fn rolling_windows_for_limits (
2088+ l : & crate :: codex_rpc:: AccountRateLimits ,
2089+ ) -> (
2090+ Option < & crate :: codex_rpc:: RateLimitWindow > ,
2091+ Option < & crate :: codex_rpc:: RateLimitWindow > ,
2092+ ) {
2093+ if l. primary . is_some ( ) || l. secondary . is_some ( ) {
2094+ return ( l. primary . as_ref ( ) , l. secondary . as_ref ( ) ) ;
2095+ }
2096+ l. buckets
2097+ . iter ( )
2098+ . find ( |bucket| bucket. primary . is_some ( ) || bucket. secondary . is_some ( ) )
2099+ . map ( |bucket| ( bucket. primary . as_ref ( ) , bucket. secondary . as_ref ( ) ) )
2100+ . unwrap_or ( ( None , None ) )
2101+ }
2102+
2103+ fn format_individual_limit_compact_lines (
2104+ l : & crate :: codex_rpc:: AccountRateLimits ,
2105+ ) -> Option < ( String , String ) > {
2106+ let individual_limit = l. individual_limit . as_ref ( ) . or_else ( || {
2107+ l. buckets
2108+ . iter ( )
2109+ . find_map ( |bucket| bucket. individual_limit . as_ref ( ) )
2110+ } ) ?;
2111+
2112+ const LABEL_W : usize = 10 ;
2113+ let remaining = individual_limit
2114+ . remaining_percent
2115+ . filter ( |v| v. is_finite ( ) )
2116+ . map ( |v| format ! ( "{}%" , v. round( ) as i64 ) )
2117+ . unwrap_or_else ( || "--%" . to_string ( ) ) ;
2118+ let resets = resets_label ( individual_limit. resets_at )
2119+ . map ( |s| format ! ( " ({s})" ) )
2120+ . unwrap_or_default ( ) ;
2121+ let monthly = format ! ( "{:<LABEL_W$}{remaining}{resets}" , "Monthly:" ) ;
2122+
2123+ let used = individual_limit
2124+ . used
2125+ . as_deref ( )
2126+ . map ( format_credit_amount)
2127+ . unwrap_or_else ( || "--" . to_string ( ) ) ;
2128+ let limit = individual_limit
2129+ . limit
2130+ . as_deref ( )
2131+ . map ( format_credit_amount)
2132+ . unwrap_or_else ( || "--" . to_string ( ) ) ;
2133+ let used_line = format ! ( "{:<LABEL_W$}{used}/{limit} used" , "Credits:" ) ;
2134+ Some ( ( monthly, used_line) )
2135+ }
2136+
20812137fn format_extra_bucket_compact_line ( l : & crate :: codex_rpc:: AccountRateLimits ) -> Option < String > {
20822138 let active_id = l. limit_id . as_deref ( ) ;
20832139 let active_name = l. limit_name . as_deref ( ) ;
@@ -2109,6 +2165,15 @@ fn compact_bucket_label(bucket: &crate::codex_rpc::RateLimitSnapshot) -> String
21092165 format ! ( "{}:" , truncate_middle( cleaned, 9 ) )
21102166}
21112167
2168+ fn format_credit_amount ( raw : & str ) -> String {
2169+ let cleaned: String = raw. chars ( ) . filter ( |c| !c. is_control ( ) ) . collect ( ) ;
2170+ let cleaned = cleaned. trim ( ) ;
2171+ let number = cleaned. parse :: < f64 > ( ) . ok ( ) . filter ( |v| v. is_finite ( ) ) ;
2172+ number
2173+ . map ( |v| format_count ( v. round ( ) as i64 ) )
2174+ . unwrap_or_else ( || truncate_middle ( cleaned, 12 ) )
2175+ }
2176+
21122177fn format_credits_compact_line ( l : & crate :: codex_rpc:: AccountRateLimits ) -> Option < String > {
21132178 const LABEL_W : usize = 10 ;
21142179 let credits = l. credits . as_ref ( ) ?;
@@ -2255,6 +2320,48 @@ mod tests {
22552320 assert_eq ! ( truncate_middle( "hello" , 3 ) , "..." ) ;
22562321 }
22572322
2323+ #[ test]
2324+ fn limits_card_uses_monthly_and_named_rolling_bucket ( ) {
2325+ let limits = crate :: codex_rpc:: AccountRateLimits {
2326+ limit_id : Some ( "codex" . to_string ( ) ) ,
2327+ limit_name : None ,
2328+ plan_type : Some ( "enterprise" . to_string ( ) ) ,
2329+ individual_limit : Some ( crate :: codex_rpc:: SpendControlLimitSnapshot {
2330+ limit : Some ( "60000" . to_string ( ) ) ,
2331+ remaining_percent : Some ( 99.0 ) ,
2332+ resets_at : None ,
2333+ used : Some ( "564" . to_string ( ) ) ,
2334+ } ) ,
2335+ primary : None ,
2336+ secondary : None ,
2337+ credits : None ,
2338+ buckets : vec ! [ crate :: codex_rpc:: RateLimitSnapshot {
2339+ limit_id: Some ( "codex_bengalfox" . to_string( ) ) ,
2340+ limit_name: Some ( "GPT-5.3-Codex-Spark-Preview" . to_string( ) ) ,
2341+ plan_type: Some ( "enterprise" . to_string( ) ) ,
2342+ individual_limit: None ,
2343+ primary: Some ( crate :: codex_rpc:: RateLimitWindow {
2344+ used_percent: Some ( 0.0 ) ,
2345+ window_duration_mins: Some ( 300.0 ) ,
2346+ resets_at: None ,
2347+ } ) ,
2348+ secondary: Some ( crate :: codex_rpc:: RateLimitWindow {
2349+ used_percent: Some ( 0.0 ) ,
2350+ window_duration_mins: Some ( 10080.0 ) ,
2351+ resets_at: None ,
2352+ } ) ,
2353+ credits: None ,
2354+ } ] ,
2355+ reset_credits_available : None ,
2356+ } ;
2357+
2358+ let ( value, caption1, caption2, caption3) = format_limits_compact_card_lines ( & limits) ;
2359+ assert_eq ! ( value, "Monthly: 99%" ) ;
2360+ assert_eq ! ( caption1. as_deref( ) , Some ( "Credits: 564/60,000 used" ) ) ;
2361+ assert_eq ! ( caption2. as_deref( ) , Some ( "5h limit: 100%" ) ) ;
2362+ assert_eq ! ( caption3. as_deref( ) , Some ( "Weekly: 100%" ) ) ;
2363+ }
2364+
22582365 #[ test]
22592366 fn horizontal_tokens_show_total_and_out_of_cache ( ) {
22602367 let out =
0 commit comments