mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-06 15:03:54 +08:00
fix(openai): skip stale and reset Codex snapshots in scheduling threshold evaluator
This commit is contained in:
@@ -53,7 +53,7 @@ func EvaluateAccountSchedulingThreshold(account *Account, thresholds map[string]
|
||||
var winner *accountSchedulingThresholdCandidate
|
||||
switch decision.Platform {
|
||||
case PlatformOpenAI:
|
||||
winner = pickLatestResetSchedulingCandidate(openAIThresholdCandidates(account), threshold, now)
|
||||
winner = pickLatestResetSchedulingCandidate(openAIThresholdCandidates(account, now), threshold, now)
|
||||
case PlatformAnthropic:
|
||||
winner = pickLatestResetSchedulingCandidate(anthropicThresholdCandidates(account), threshold, now)
|
||||
case PlatformGrok:
|
||||
@@ -149,7 +149,7 @@ func lookupAccountSchedulingThreshold(thresholds map[string]int, platform string
|
||||
return value, ok
|
||||
}
|
||||
|
||||
func openAIThresholdCandidates(account *Account) []*accountSchedulingThresholdCandidate {
|
||||
func openAIThresholdCandidates(account *Account, now time.Time) []*accountSchedulingThresholdCandidate {
|
||||
if account == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -157,8 +157,8 @@ func openAIThresholdCandidates(account *Account) []*accountSchedulingThresholdCa
|
||||
return nil
|
||||
}
|
||||
return []*accountSchedulingThresholdCandidate{
|
||||
openAIThresholdCandidate(account.Extra, "5h"),
|
||||
openAIThresholdCandidate(account.Extra, "7d"),
|
||||
openAIThresholdCandidate(account.Extra, "5h", now),
|
||||
openAIThresholdCandidate(account.Extra, "7d", now),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ func firstStringValue(values map[string]any, keys ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func openAIThresholdCandidate(extra map[string]any, window string) *accountSchedulingThresholdCandidate {
|
||||
func openAIThresholdCandidate(extra map[string]any, window string, now time.Time) *accountSchedulingThresholdCandidate {
|
||||
if len(extra) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -243,6 +243,9 @@ func openAIThresholdCandidate(extra map[string]any, window string) *accountSched
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if openAIQuotaWindowReset(extra, window, now) || openAICodexSnapshotStaleForPause(extra, now) {
|
||||
return nil
|
||||
}
|
||||
return &accountSchedulingThresholdCandidate{
|
||||
window: window,
|
||||
usedPercent: schedulingPercentValue(usedPercent),
|
||||
|
||||
@@ -109,7 +109,7 @@ func TestEvaluateAccountSchedulingThreshold_OpenAIPreservesPercentageSemantics(t
|
||||
},
|
||||
}
|
||||
|
||||
candidate := openAIThresholdCandidate(openAIAccount.Extra, "5h")
|
||||
candidate := openAIThresholdCandidate(openAIAccount.Extra, "5h", now)
|
||||
require.NotNil(t, candidate)
|
||||
require.Equal(t, 1.0, candidate.usedPercent)
|
||||
|
||||
@@ -126,6 +126,88 @@ func TestEvaluateAccountSchedulingThreshold_OpenAIPreservesPercentageSemantics(t
|
||||
require.Equal(t, 91.0, openAIDecision.UsedPercent)
|
||||
}
|
||||
|
||||
func TestEvaluateAccountSchedulingThreshold_OpenAISkipsStaleSnapshot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Date(2026, 6, 3, 12, 0, 0, 0, time.UTC)
|
||||
account := &Account{
|
||||
Platform: PlatformOpenAI,
|
||||
Extra: map[string]any{
|
||||
"codex_usage_updated_at": now.Add(-2 * time.Hour).Format(time.RFC3339),
|
||||
"codex_5h_used_percent": 100.0,
|
||||
"codex_5h_reset_at": now.Add(3 * time.Hour).Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
|
||||
decision := EvaluateAccountSchedulingThreshold(account, map[string]int{PlatformOpenAI: 90}, now)
|
||||
|
||||
require.False(t, decision.ShouldPause)
|
||||
}
|
||||
|
||||
func TestEvaluateAccountSchedulingThreshold_OpenAISkipsResetWindow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Date(2026, 6, 3, 12, 0, 0, 0, time.UTC)
|
||||
account := &Account{
|
||||
Platform: PlatformOpenAI,
|
||||
Extra: map[string]any{
|
||||
"codex_usage_updated_at": now.Add(-time.Minute).Format(time.RFC3339),
|
||||
"codex_5h_used_percent": 100.0,
|
||||
"codex_5h_reset_at": now.Add(-time.Second).Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
|
||||
decision := EvaluateAccountSchedulingThreshold(account, map[string]int{PlatformOpenAI: 90}, now)
|
||||
|
||||
require.False(t, decision.ShouldPause)
|
||||
}
|
||||
|
||||
func TestEvaluateAccountSchedulingThreshold_OpenAIPausesFreshExhaustedSnapshot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Date(2026, 6, 3, 12, 0, 0, 0, time.UTC)
|
||||
resetAt := now.Add(3 * time.Hour)
|
||||
account := &Account{
|
||||
Platform: PlatformOpenAI,
|
||||
Extra: map[string]any{
|
||||
"codex_usage_updated_at": now.Add(-time.Minute).Format(time.RFC3339),
|
||||
"codex_5h_used_percent": 100.0,
|
||||
"codex_5h_reset_at": resetAt.Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
|
||||
decision := EvaluateAccountSchedulingThreshold(account, map[string]int{PlatformOpenAI: 90}, now)
|
||||
|
||||
require.True(t, decision.ShouldPause)
|
||||
require.Equal(t, "5h", decision.Window)
|
||||
require.Equal(t, 100.0, decision.UsedPercent)
|
||||
require.NotNil(t, decision.Until)
|
||||
require.True(t, resetAt.Equal(*decision.Until))
|
||||
}
|
||||
|
||||
func TestEvaluateAccountSchedulingThreshold_OpenAIPausesFreshExhaustedSevenDayWindow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Date(2026, 6, 3, 12, 0, 0, 0, time.UTC)
|
||||
resetAt := now.Add(5 * 24 * time.Hour)
|
||||
account := &Account{
|
||||
Platform: PlatformOpenAI,
|
||||
Extra: map[string]any{
|
||||
"codex_usage_updated_at": now.Add(-time.Minute).Format(time.RFC3339),
|
||||
"codex_7d_used_percent": 95.0,
|
||||
"codex_7d_reset_at": resetAt.Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
|
||||
decision := EvaluateAccountSchedulingThreshold(account, map[string]int{PlatformOpenAI: 90}, now)
|
||||
|
||||
require.True(t, decision.ShouldPause)
|
||||
require.Equal(t, "7d", decision.Window)
|
||||
require.Equal(t, 95.0, decision.UsedPercent)
|
||||
require.NotNil(t, decision.Until)
|
||||
require.True(t, resetAt.Equal(*decision.Until))
|
||||
}
|
||||
|
||||
func TestEvaluateAccountSchedulingThreshold_AnthropicPreservesFractionalUtilizationSemantics(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user