maodd commited on
Commit
c9fc314
·
verified ·
1 Parent(s): 8b1ef20

Fix rate limiter to throttle every call, not just after N

Browse files

Confirmed via AI Studio dashboard: gemini-3.6-flash free tier caps at 5 RPM. Old limiter allowed unthrottled bursts up to 15 calls before pausing, which 429'd. New limiter enforces a minimum delay between every single call.

Files changed (1) hide show
  1. app.py +17 -15
app.py CHANGED
@@ -24,7 +24,7 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
24
  @spaces.GPU
25
  def _zerogpu_startup_check():
26
  # This Space runs on ZeroGPU hardware but the agent below only makes
27
- # network calls (Claude API, web search) and never touches CUDA.
28
  # ZeroGPU requires at least one @spaces.GPU function to be declared,
29
  # so this no-op satisfies that check without spending any GPU quota
30
  # (it is never actually invoked).
@@ -41,22 +41,24 @@ If you are asked for a comma separated list, apply the above rules to each eleme
41
 
42
  class RateLimiter:
43
  """
44
- Counts agent LLM calls (one per step) and sleeps for a fixed duration
45
- once a threshold is reached, then resets the counter. Used as a
46
- step_callback to stay under the model provider's rate limits across a
47
- full run of ~20 GAIA questions, each potentially taking several steps.
 
48
  """
49
- def __init__(self, calls_per_wait: int = 15, seconds_to_wait: int = 30):
50
- self.calls_per_wait = calls_per_wait
51
- self.seconds_to_wait = seconds_to_wait
52
- self._call_count = 0
53
 
54
  def __call__(self, memory_step: ActionStep, agent: CodeAgent) -> None:
55
- self._call_count += 1
56
- if self._call_count >= self.calls_per_wait:
57
- print(f"Rate limiter: {self.calls_per_wait} calls reached, sleeping {self.seconds_to_wait}s")
58
- time.sleep(self.seconds_to_wait)
59
- self._call_count = 0
 
 
60
 
61
 
62
  # --- Basic Agent Definition ---
@@ -78,7 +80,7 @@ class BasicAgent:
78
  "collections", "statistics", "datetime", "io", "openpyxl", "PIL",
79
  ],
80
  max_steps=12,
81
- step_callbacks=[RateLimiter()],
82
  )
83
  print("BasicAgent initialized.")
84
 
 
24
  @spaces.GPU
25
  def _zerogpu_startup_check():
26
  # This Space runs on ZeroGPU hardware but the agent below only makes
27
+ # network calls (Gemini API, web search) and never touches CUDA.
28
  # ZeroGPU requires at least one @spaces.GPU function to be declared,
29
  # so this no-op satisfies that check without spending any GPU quota
30
  # (it is never actually invoked).
 
41
 
42
  class RateLimiter:
43
  """
44
+ Enforces a minimum delay between successive agent LLM calls (one call per
45
+ step) as a step_callback, to stay under the model provider's
46
+ requests-per-minute limit. Gemini's free tier for gemini-3.6-flash caps
47
+ at 5 RPM, so the default here (12s + margin) targets that; override via
48
+ RATE_LIMIT_SECONDS_BETWEEN_CALLS if your tier/model allows more.
49
  """
50
+ def __init__(self, min_seconds_between_calls: float = 13.0):
51
+ self.min_seconds_between_calls = min_seconds_between_calls
52
+ self._last_call_at: float | None = None
 
53
 
54
  def __call__(self, memory_step: ActionStep, agent: CodeAgent) -> None:
55
+ now = time.monotonic()
56
+ if self._last_call_at is not None:
57
+ wait = self.min_seconds_between_calls - (now - self._last_call_at)
58
+ if wait > 0:
59
+ print(f"Rate limiter: sleeping {wait:.1f}s to stay under the RPM limit")
60
+ time.sleep(wait)
61
+ self._last_call_at = time.monotonic()
62
 
63
 
64
  # --- Basic Agent Definition ---
 
80
  "collections", "statistics", "datetime", "io", "openpyxl", "PIL",
81
  ],
82
  max_steps=12,
83
+ step_callbacks=[RateLimiter(float(os.getenv("RATE_LIMIT_SECONDS_BETWEEN_CALLS", "13.0")))],
84
  )
85
  print("BasicAgent initialized.")
86