From 7e8967decbc8221694953abf1435fda8aaf18824 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Thu, 19 Mar 2026 23:03:56 +0000 Subject: feat: agent status dashboard with availability timeline and Gemini quota detection - Detect Gemini TerminalQuotaError (daily quota) as BUDGET_EXCEEDED, not generic FAILED - Surface container stderr tail in error so quota/rate-limit classifiers can match it - Add agent_events table to persist rate-limit start/recovery events across restarts - Add GET /api/agents/status endpoint returning live agent state + 24h event history - Stats dashboard: agent status cards, 24h availability timeline, per-run execution table Co-Authored-By: Claude Sonnet 4.6 --- internal/executor/ratelimit_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'internal/executor/ratelimit_test.go') diff --git a/internal/executor/ratelimit_test.go b/internal/executor/ratelimit_test.go index f45216f..1434810 100644 --- a/internal/executor/ratelimit_test.go +++ b/internal/executor/ratelimit_test.go @@ -77,6 +77,36 @@ func TestParseRetryAfter_NoRetryInfo(t *testing.T) { } } +// --- isQuotaExhausted tests --- + +func TestIsQuotaExhausted_GeminiDailyQuota(t *testing.T) { + err := errors.New("container execution failed: exit status 1\nTerminalQuotaError: You have exhausted your daily quota on this model.") + if !isQuotaExhausted(err) { + t.Error("want true for Gemini TerminalQuotaError, got false") + } +} + +func TestIsQuotaExhausted_GeminiExhaustedMessage(t *testing.T) { + err := errors.New("container execution failed: exit status 1\nyou have exhausted your daily quota") + if !isQuotaExhausted(err) { + t.Error("want true for 'exhausted your daily quota', got false") + } +} + +func TestIsQuotaExhausted_GeminiQuotaExceeded(t *testing.T) { + err := errors.New("container execution failed: exit status 1\nQuota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_requests") + if !isQuotaExhausted(err) { + t.Error("want true for Gemini free tier quota exceeded, got false") + } +} + +func TestIsQuotaExhausted_NotQuota(t *testing.T) { + err := errors.New("container execution failed: exit status 1") + if isQuotaExhausted(err) { + t.Error("want false for generic exit status 1, got true") + } +} + // --- runWithBackoff tests --- func TestRunWithBackoff_SuccessOnFirstTry(t *testing.T) { -- cgit v1.2.3