From a8ffb052ca5fcaf9a3e53eba4e83bedcf2a8e8a4 Mon Sep 17 00:00:00 2001 From: ghostg00 <28946120+ghostg00@users.noreply.github.com> Date: Wed, 3 Jun 2026 11:37:55 +0800 Subject: [PATCH] =?UTF-8?q?Revert=20"fix(usage):=20=E4=BF=AE=E6=AD=A3=20Op?= =?UTF-8?q?enAI=205h=20=E7=94=A8=E9=87=8F=E7=99=BE=E5=88=86=E6=AF=94?= =?UTF-8?q?=E8=AF=AD=E4=B9=89"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b65dde634bf7a5338f22b46ad0f9d98a197526fc. --- .../account_test_service_openai_test.go | 4 +-- .../service/account_usage_service_test.go | 29 +--------------- .../service/openai_gateway_service.go | 17 ++-------- ...nai_gateway_service_codex_snapshot_test.go | 34 ------------------- .../service/openai_gateway_service_test.go | 2 +- .../service/ratelimit_service_openai_test.go | 32 ++++++++--------- 6 files changed, 22 insertions(+), 96 deletions(-) diff --git a/backend/internal/service/account_test_service_openai_test.go b/backend/internal/service/account_test_service_openai_test.go index 970c723a..910567fb 100644 --- a/backend/internal/service/account_test_service_openai_test.go +++ b/backend/internal/service/account_test_service_openai_test.go @@ -132,7 +132,7 @@ func TestAccountTestService_OpenAISuccessPersistsSnapshotFromHeaders(t *testing. require.Len(t, upstream.requests, 1) require.Equal(t, HTTPUpstreamProfileOpenAI, HTTPUpstreamProfileFromContext(upstream.requests[0].Context())) require.NotEmpty(t, repo.updatedExtra) - require.Equal(t, 58.0, repo.updatedExtra["codex_5h_used_percent"]) + require.Equal(t, 42.0, repo.updatedExtra["codex_5h_used_percent"]) require.Equal(t, 88.0, repo.updatedExtra["codex_7d_used_percent"]) require.Contains(t, recorder.Body.String(), "test_complete") } @@ -170,7 +170,7 @@ func TestAccountTestService_OpenAI429PersistsSnapshotAndRateLimitState(t *testin resp.Header.Set("x-codex-primary-used-percent", "100") resp.Header.Set("x-codex-primary-reset-after-seconds", "604800") resp.Header.Set("x-codex-primary-window-minutes", "10080") - resp.Header.Set("x-codex-secondary-used-percent", "0") + resp.Header.Set("x-codex-secondary-used-percent", "100") resp.Header.Set("x-codex-secondary-reset-after-seconds", "18000") resp.Header.Set("x-codex-secondary-window-minutes", "300") diff --git a/backend/internal/service/account_usage_service_test.go b/backend/internal/service/account_usage_service_test.go index 5f37aadb..e0390c4c 100644 --- a/backend/internal/service/account_usage_service_test.go +++ b/backend/internal/service/account_usage_service_test.go @@ -73,7 +73,7 @@ func TestExtractOpenAICodexProbeUpdatesAccepts429WithCodexHeaders(t *testing.T) headers.Set("x-codex-primary-used-percent", "100") headers.Set("x-codex-primary-reset-after-seconds", "604800") headers.Set("x-codex-primary-window-minutes", "10080") - headers.Set("x-codex-secondary-used-percent", "0") + headers.Set("x-codex-secondary-used-percent", "100") headers.Set("x-codex-secondary-reset-after-seconds", "18000") headers.Set("x-codex-secondary-window-minutes", "300") @@ -92,33 +92,6 @@ func TestExtractOpenAICodexProbeUpdatesAccepts429WithCodexHeaders(t *testing.T) } } -func TestBuildCodexUsageProgressFromExtra_UsesCanonicalUsedPercent(t *testing.T) { - t.Parallel() - now := time.Date(2026, 5, 30, 7, 4, 9, 0, time.UTC) - extra := map[string]any{ - "codex_5h_used_percent": 94.0, - "codex_5h_reset_at": now.Add(2 * time.Hour).Format(time.RFC3339), - "codex_7d_used_percent": 93.0, - "codex_7d_reset_at": now.Add(5 * 24 * time.Hour).Format(time.RFC3339), - } - - fiveHour := buildCodexUsageProgressFromExtra(extra, "5h", now) - if fiveHour == nil { - t.Fatal("expected non-nil 5h progress") - } - if fiveHour.Utilization != 94.0 { - t.Fatalf("5h Utilization = %v, want 94", fiveHour.Utilization) - } - - sevenDay := buildCodexUsageProgressFromExtra(extra, "7d", now) - if sevenDay == nil { - t.Fatal("expected non-nil 7d progress") - } - if sevenDay.Utilization != 93.0 { - t.Fatalf("7d Utilization = %v, want 93", sevenDay.Utilization) - } -} - func TestAccountUsageService_PersistOpenAICodexProbeSnapshotOnlyUpdatesExtra(t *testing.T) { t.Parallel() diff --git a/backend/internal/service/openai_gateway_service.go b/backend/internal/service/openai_gateway_service.go index b1a95594..17ac7fc2 100644 --- a/backend/internal/service/openai_gateway_service.go +++ b/backend/internal/service/openai_gateway_service.go @@ -126,19 +126,6 @@ type NormalizedCodexLimits struct { Window7dMinutes *int } -func normalizeCodexFiveHourUsedPercent(raw *float64) *float64 { - if raw == nil { - return nil - } - // OpenAI's 5h Codex quota header is remaining%, despite the upstream header - // name saying "used"; the canonical codex_5h_used_percent field stores used%. - used := 100 - *raw - if used < 0 { - used = 0 - } - return &used -} - // Normalize converts primary/secondary fields to canonical 5h/7d fields. // Strategy: Compare window_minutes to determine which is 5h vs 7d. // Returns nil if snapshot is nil or has no useful data. @@ -197,7 +184,7 @@ func (s *OpenAICodexUsageSnapshot) Normalize() *NormalizedCodexLimits { // Assign values if use5hFromPrimary { - result.Used5hPercent = normalizeCodexFiveHourUsedPercent(s.PrimaryUsedPercent) + result.Used5hPercent = s.PrimaryUsedPercent result.Reset5hSeconds = s.PrimaryResetAfterSeconds result.Window5hMinutes = s.PrimaryWindowMinutes result.Used7dPercent = s.SecondaryUsedPercent @@ -207,7 +194,7 @@ func (s *OpenAICodexUsageSnapshot) Normalize() *NormalizedCodexLimits { result.Used7dPercent = s.PrimaryUsedPercent result.Reset7dSeconds = s.PrimaryResetAfterSeconds result.Window7dMinutes = s.PrimaryWindowMinutes - result.Used5hPercent = normalizeCodexFiveHourUsedPercent(s.SecondaryUsedPercent) + result.Used5hPercent = s.SecondaryUsedPercent result.Reset5hSeconds = s.SecondaryResetAfterSeconds result.Window5hMinutes = s.SecondaryWindowMinutes } diff --git a/backend/internal/service/openai_gateway_service_codex_snapshot_test.go b/backend/internal/service/openai_gateway_service_codex_snapshot_test.go index 22f5fa74..654dd4ca 100644 --- a/backend/internal/service/openai_gateway_service_codex_snapshot_test.go +++ b/backend/internal/service/openai_gateway_service_codex_snapshot_test.go @@ -104,40 +104,6 @@ func TestBuildCodexUsageExtraUpdates_UsesSnapshotUpdatedAt(t *testing.T) { } } -func TestBuildCodexUsageExtraUpdates_NormalizesFiveHourRemainingToUsedPercent(t *testing.T) { - primaryUsed := 93.0 - primaryReset := 86400 - primaryWindow := 10080 - secondaryRemaining := 6.0 - secondaryReset := 3600 - secondaryWindow := 300 - - snapshot := &OpenAICodexUsageSnapshot{ - PrimaryUsedPercent: &primaryUsed, - PrimaryResetAfterSeconds: &primaryReset, - PrimaryWindowMinutes: &primaryWindow, - SecondaryUsedPercent: &secondaryRemaining, - SecondaryResetAfterSeconds: &secondaryReset, - SecondaryWindowMinutes: &secondaryWindow, - UpdatedAt: "2026-05-30T07:04:09Z", - } - - updates := buildCodexUsageExtraUpdates(snapshot, time.Time{}) - if updates == nil { - t.Fatal("expected non-nil updates") - } - - if got := updates["codex_secondary_used_percent"]; got != 6.0 { - t.Fatalf("codex_secondary_used_percent = %v, want raw upstream value 6", got) - } - if got := updates["codex_5h_used_percent"]; got != 94.0 { - t.Fatalf("codex_5h_used_percent = %v, want 94", got) - } - if got := updates["codex_7d_used_percent"]; got != 93.0 { - t.Fatalf("codex_7d_used_percent = %v, want 93", got) - } -} - func TestBuildCodexUsageExtraUpdates_FallbackToNowWhenUpdatedAtInvalid(t *testing.T) { primaryUsed := 15.0 primaryReset := 30 diff --git a/backend/internal/service/openai_gateway_service_test.go b/backend/internal/service/openai_gateway_service_test.go index 5c4e979d..8aad2fa6 100644 --- a/backend/internal/service/openai_gateway_service_test.go +++ b/backend/internal/service/openai_gateway_service_test.go @@ -1774,7 +1774,7 @@ func TestOpenAIUpdateCodexUsageSnapshotFromHeaders(t *testing.T) { select { case updates := <-repo.updateExtraCalls: - require.Equal(t, 88.0, updates["codex_5h_used_percent"]) + require.Equal(t, 12.0, updates["codex_5h_used_percent"]) require.Equal(t, 34.0, updates["codex_7d_used_percent"]) require.Equal(t, 600, updates["codex_5h_reset_after_seconds"]) require.Equal(t, 86400, updates["codex_7d_reset_after_seconds"]) diff --git a/backend/internal/service/ratelimit_service_openai_test.go b/backend/internal/service/ratelimit_service_openai_test.go index 107ac27e..aa5a070c 100644 --- a/backend/internal/service/ratelimit_service_openai_test.go +++ b/backend/internal/service/ratelimit_service_openai_test.go @@ -51,7 +51,7 @@ func TestCalculateOpenAI429ResetTime_5hExhausted(t *testing.T) { headers.Set("x-codex-primary-used-percent", "50") headers.Set("x-codex-primary-reset-after-seconds", "500000") headers.Set("x-codex-primary-window-minutes", "10080") // 7 days - headers.Set("x-codex-secondary-used-percent", "0") + headers.Set("x-codex-secondary-used-percent", "100") headers.Set("x-codex-secondary-reset-after-seconds", "3600") // 1 hour headers.Set("x-codex-secondary-window-minutes", "300") // 5 hours @@ -122,7 +122,7 @@ func TestCalculateOpenAI429ResetTime_ReversedWindowOrder(t *testing.T) { // Test when OpenAI sends primary as 5h and secondary as 7d (reversed) headers := http.Header{} - headers.Set("x-codex-primary-used-percent", "0") // This is 5h remaining% + headers.Set("x-codex-primary-used-percent", "100") // This is 5h headers.Set("x-codex-primary-reset-after-seconds", "3600") // 1 hour headers.Set("x-codex-primary-window-minutes", "300") // 5 hours - smaller! headers.Set("x-codex-secondary-used-percent", "50") @@ -180,7 +180,7 @@ func TestHandle429_OpenAIPersistsCodexSnapshotImmediately(t *testing.T) { headers.Set("x-codex-primary-used-percent", "100") headers.Set("x-codex-primary-reset-after-seconds", "604800") headers.Set("x-codex-primary-window-minutes", "10080") - headers.Set("x-codex-secondary-used-percent", "0") + headers.Set("x-codex-secondary-used-percent", "100") headers.Set("x-codex-secondary-reset-after-seconds", "18000") headers.Set("x-codex-secondary-window-minutes", "300") @@ -224,7 +224,7 @@ func TestNormalizedCodexLimits(t *testing.T) { pUsed := 100.0 pReset := 384607 pWindow := 10080 - sRemaining := 3.0 + sUsed := 3.0 sReset := 17369 sWindow := 300 @@ -232,7 +232,7 @@ func TestNormalizedCodexLimits(t *testing.T) { PrimaryUsedPercent: &pUsed, PrimaryResetAfterSeconds: &pReset, PrimaryWindowMinutes: &pWindow, - SecondaryUsedPercent: &sRemaining, + SecondaryUsedPercent: &sUsed, SecondaryResetAfterSeconds: &sReset, SecondaryWindowMinutes: &sWindow, } @@ -249,8 +249,8 @@ func TestNormalizedCodexLimits(t *testing.T) { if normalized.Reset7dSeconds == nil || *normalized.Reset7dSeconds != 384607 { t.Errorf("expected Reset7dSeconds=384607, got %v", normalized.Reset7dSeconds) } - if normalized.Used5hPercent == nil || *normalized.Used5hPercent != 97.0 { - t.Errorf("expected Used5hPercent=97, got %v", normalized.Used5hPercent) + if normalized.Used5hPercent == nil || *normalized.Used5hPercent != 3.0 { + t.Errorf("expected Used5hPercent=3, got %v", normalized.Used5hPercent) } if normalized.Reset5hSeconds == nil || *normalized.Reset5hSeconds != 17369 { t.Errorf("expected Reset5hSeconds=17369, got %v", normalized.Reset5hSeconds) @@ -338,11 +338,11 @@ func TestRateLimitService_HandleUpstreamError_403FallsBackToRawBody(t *testing.T func TestNormalizedCodexLimits_OnlySecondaryData(t *testing.T) { // Test when only secondary has data, no window_minutes - sRemaining := 60.0 + sUsed := 60.0 sReset := 3000 snapshot := &OpenAICodexUsageSnapshot{ - SecondaryUsedPercent: &sRemaining, + SecondaryUsedPercent: &sUsed, SecondaryResetAfterSeconds: &sReset, // No window_minutes, no primary data } @@ -354,8 +354,8 @@ func TestNormalizedCodexLimits_OnlySecondaryData(t *testing.T) { // Legacy assumption: primary=7d, secondary=5h // So secondary goes to 5h - if normalized.Used5hPercent == nil || *normalized.Used5hPercent != 40.0 { - t.Errorf("expected Used5hPercent=40, got %v", normalized.Used5hPercent) + if normalized.Used5hPercent == nil || *normalized.Used5hPercent != 60.0 { + t.Errorf("expected Used5hPercent=60, got %v", normalized.Used5hPercent) } if normalized.Reset5hSeconds == nil || *normalized.Reset5hSeconds != 3000 { t.Errorf("expected Reset5hSeconds=3000, got %v", normalized.Reset5hSeconds) @@ -370,13 +370,13 @@ func TestNormalizedCodexLimits_BothDataNoWindowMinutes(t *testing.T) { // Test when both have data but no window_minutes pUsed := 100.0 pReset := 400000 - sRemaining := 30.0 + sUsed := 50.0 sReset := 10000 snapshot := &OpenAICodexUsageSnapshot{ PrimaryUsedPercent: &pUsed, PrimaryResetAfterSeconds: &pReset, - SecondaryUsedPercent: &sRemaining, + SecondaryUsedPercent: &sUsed, SecondaryResetAfterSeconds: &sReset, // No window_minutes } @@ -393,8 +393,8 @@ func TestNormalizedCodexLimits_BothDataNoWindowMinutes(t *testing.T) { if normalized.Reset7dSeconds == nil || *normalized.Reset7dSeconds != 400000 { t.Errorf("expected Reset7dSeconds=400000, got %v", normalized.Reset7dSeconds) } - if normalized.Used5hPercent == nil || *normalized.Used5hPercent != 70.0 { - t.Errorf("expected Used5hPercent=70, got %v", normalized.Used5hPercent) + if normalized.Used5hPercent == nil || *normalized.Used5hPercent != 50.0 { + t.Errorf("expected Used5hPercent=50, got %v", normalized.Used5hPercent) } if normalized.Reset5hSeconds == nil || *normalized.Reset5hSeconds != 10000 { t.Errorf("expected Reset5hSeconds=10000, got %v", normalized.Reset5hSeconds) @@ -425,7 +425,7 @@ func TestCalculateOpenAI429ResetTime_UserProvidedScenario(t *testing.T) { // This is the exact scenario from the user: // codex_7d_used_percent: 100 // codex_7d_reset_after_seconds: 384607 (约4.5天后重置) - // codex_5h_used_percent: 97 (from upstream 3% remaining) + // codex_5h_used_percent: 3 // codex_5h_reset_after_seconds: 17369 (约4.8小时后重置) svc := &RateLimitService{}