@@ -277,6 +277,7 @@ type AccountUsageStatus struct {
277277 Windows []accounts.UsageWindow `json:"windows,omitempty"`
278278 Credits * accounts.CreditsInfo `json:"credits,omitempty"`
279279 ComplimentaryReset * accounts.ComplimentaryResetInfo `json:"complimentary_reset,omitempty"`
280+ UsageFresh bool `json:"-"`
280281}
281282
282283func NewAccountRef (store accounts.CodexStore , initial []accounts.Account , client * http.Client ) * AccountRef {
@@ -488,6 +489,7 @@ func (r *AccountRef) UsageStatuses(ctx context.Context) []AccountUsageStatus {
488489 restored .Active = status .Active
489490 restored .Refreshed = status .Refreshed
490491 restored .Error = ""
492+ restored .UsageFresh = false
491493 out [i ] = restored
492494 }
493495 r .usageStatusCache = append ([]AccountUsageStatus (nil ), out ... )
@@ -592,6 +594,7 @@ func (r *AccountRef) usageStatusesLive(ctx context.Context) []AccountUsageStatus
592594 next .Windows = details .Windows
593595 next .Credits = details .Credits
594596 next .ComplimentaryReset = details .ComplimentaryReset
597+ next .UsageFresh = true
595598 out [i ] = next
596599 }()
597600 }
@@ -628,14 +631,15 @@ func (r *AccountRef) usageStatusesLive(ctx context.Context) []AccountUsageStatus
628631 }
629632 next .AuthValid = true
630633 r .replace (account )
631- windows , _ , err := r .FetchUsageWindowsCached (ctx , r .client , account )
634+ windows , fresh , err := r .FetchUsageWindowsCached (ctx , r .client , account )
632635 if err != nil {
633636 next .Error = err .Error ()
634637 out [i ] = next
635638 return
636639 }
637640 next .PlanType = "claude"
638641 next .Windows = windows
642+ next .UsageFresh = fresh
639643 out [i ] = next
640644 }()
641645 }
@@ -953,7 +957,9 @@ func (s Server) handleUsageStatus(w http.ResponseWriter, r *http.Request) {
953957 return
954958 }
955959 if s .AccountRef != nil {
956- writeJSON (w , s .withRequestTimeExhaustionWindows (s .AccountRef .UsageStatuses (r .Context ())))
960+ statuses := s .AccountRef .UsageStatuses (r .Context ())
961+ s .updateSchedulerFromUsageStatuses (statuses )
962+ writeJSON (w , s .withRequestTimeExhaustionWindows (statuses ))
957963 return
958964 }
959965 accounts := s .accountList ()
@@ -972,6 +978,47 @@ func (s Server) handleUsageStatus(w http.ResponseWriter, r *http.Request) {
972978 writeJSON (w , s .withRequestTimeExhaustionWindows (out ))
973979}
974980
981+ func (s Server ) updateSchedulerFromUsageStatuses (statuses []AccountUsageStatus ) {
982+ if s .SchedulerRef == nil {
983+ return
984+ }
985+ available := oauthAccounts (s .accountList ())
986+ if len (available ) == 0 {
987+ return
988+ }
989+ current := s .scheduler ()
990+ scores := make ([]selectacct.Score , 0 , len (available ))
991+ scoreByID := make (map [string ]int , len (available ))
992+ for _ , account := range available {
993+ seed := current .ScoreFor (account .Provider , account .ID )
994+ seed .AccountID = account .ID
995+ seed .Provider = account .Provider
996+ seed .Fresh = false
997+ scoreByID [selectacct .ScoreKey (account .Provider , account .ID )] = len (scores )
998+ scores = append (scores , seed )
999+ }
1000+ scored := 0
1001+ for _ , status := range statuses {
1002+ if ! status .UsageFresh || status .AuthMode != accounts .AuthModeOAuth || len (status .Windows ) == 0 {
1003+ continue
1004+ }
1005+ if idx , ok := scoreByID [selectacct .ScoreKey (status .Provider , status .ID )]; ok {
1006+ next := scoreFromUsageWindows (status .Provider , status .ID , status .Windows )
1007+ next .Fresh = true
1008+ scores [idx ] = next
1009+ scored ++
1010+ }
1011+ }
1012+ if scored == 0 {
1013+ return
1014+ }
1015+ scheduler := selectacct .NewScheduler (scores )
1016+ if s .Sessions != nil {
1017+ scheduler = scheduler .WithSessionCounts (s .Sessions .CountByAccount ())
1018+ }
1019+ s .SchedulerRef .Set (scheduler )
1020+ }
1021+
9751022func (s Server ) withRequestTimeExhaustionWindows (statuses []AccountUsageStatus ) []AccountUsageStatus {
9761023 if s .SchedulerRef == nil {
9771024 return statuses
0 commit comments