Merge pull request '[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/ratelimit/RFC.md fully. Find ONE fe...' (#19) from agent/read---spec-code-core-go-ratelimit-rfc-m into dev
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

This commit is contained in:
Virgil 2026-04-01 04:47:40 +00:00
commit cb6bb17378
2 changed files with 21 additions and 10 deletions

View file

@ -590,15 +590,6 @@ func (rl *RateLimiter) AllStats() map[string]ModelStats {
// Decide returns structured allow/deny information for an estimated request.
// It never records usage; call RecordUsage after a successful decision.
func (rl *RateLimiter) Decide(model string, estimatedTokens int) Decision {
if estimatedTokens < 0 {
return Decision{
Allowed: false,
Code: DecisionInvalidTokens,
Reason: "estimated tokens must be non-negative",
Stats: rl.Stats(model),
}
}
rl.mu.Lock()
defer rl.mu.Unlock()
@ -615,6 +606,13 @@ func (rl *RateLimiter) Decide(model string, estimatedTokens int) Decision {
}
if quota.MaxRPM == 0 && quota.MaxTPM == 0 && quota.MaxRPD == 0 {
if estimatedTokens < 0 {
decision.Allowed = false
decision.Code = DecisionInvalidTokens
decision.Reason = "estimated tokens must be non-negative"
decision.Stats = rl.snapshotLocked(model)
return decision
}
decision.Allowed = true
decision.Code = DecisionUnlimited
decision.Reason = "all limits are unlimited"
@ -629,6 +627,14 @@ func (rl *RateLimiter) Decide(model string, estimatedTokens int) Decision {
rl.State[model] = stats
}
if estimatedTokens < 0 {
decision.Allowed = false
decision.Code = DecisionInvalidTokens
decision.Reason = "estimated tokens must be non-negative"
decision.Stats = rl.snapshotLocked(model)
return decision
}
decision.Stats = rl.snapshotLocked(model)
if quota.MaxRPD > 0 && stats.DayCount >= quota.MaxRPD {

View file

@ -363,12 +363,17 @@ func TestRatelimit_Decide_Good(t *testing.T) {
t.Run("negative estimate returns invalid decision", func(t *testing.T) {
rl := newTestLimiter(t)
model := "neg"
rl.Quotas[model] = ModelQuota{MaxRPM: 5, MaxTPM: 50, MaxRPD: 5}
decision := rl.Decide("neg", -5)
decision := rl.Decide(model, -5)
assert.False(t, decision.Allowed)
assert.Equal(t, DecisionInvalidTokens, decision.Code)
assert.Zero(t, decision.RetryAfter)
require.Contains(t, rl.State, model)
require.NotNil(t, rl.State[model])
assert.Equal(t, 0, rl.State[model].DayCount)
})
}