feat: add auth health status tracking and Kiro quota query#24
Merged
rensumo merged 2 commits intoVe-ria:devfrom May 9, 2026
Merged
feat: add auth health status tracking and Kiro quota query#24rensumo merged 2 commits intoVe-ria:devfrom
rensumo merged 2 commits intoVe-ria:devfrom
Conversation
Resolves router-for-me#23 ## Health Status Tracking (recent_requests) Add per-auth request success/failure tracking via a 20-bucket ring buffer (10-minute intervals, 200-minute sliding window). The /v0/management/auth-files endpoint now returns 'success', 'failed', and 'recent_requests' fields for each auth entry, enabling the management panel to render health status indicators (red/green/yellow bars). Changes: - sdk/cliproxy/auth/types.go: Add Success/Failed counters, recentRequestRing type, RecentRequestBucket export type, recordRecentRequest() and RecentRequestsSnapshot() methods to Auth struct. - sdk/cliproxy/auth/conductor.go: Call recordRecentRequest() and increment counters in MarkResult(); preserve counters across auth reloads. - internal/api/handlers/management/auth_files.go: Expose success, failed, and recent_requests in buildAuthFileEntry() response. ## Kiro Quota Query Add a management API endpoint and background cache for querying Kiro (AWS CodeWhisperer) usage quota per auth entry. - GET /v0/management/kiro-quota?auth_index=<INDEX>: Returns usage breakdown, remaining quota, usage percentage, subscription info, and next reset time. - kiro_quota field in /v0/management/auth-files: Each Kiro auth entry now includes cached quota info (plan, used, limit, remaining, percentage). - Background refresher: Quota data is refreshed every 5 minutes for all active Kiro credentials. Changes: - internal/api/handlers/management/kiro_quota.go: GetKiroQuota handler, findKiroAuth, extractKiroTokenData, buildKiroQuotaStatus helpers. - internal/api/handlers/management/kiro_quota_cache.go: Background quota cache with StartKiroQuotaRefresher goroutine. - internal/api/server.go: Register /kiro-quota route and start refresher.
|
This pull request targeted The base branch has been automatically changed to |
There was a problem hiding this comment.
Pull request overview
This PR extends the management API with (1) per-auth request health tracking (success/failed totals + 20-bucket recent history) and (2) Kiro (AWS CodeWhisperer) quota visibility via a new endpoint and cached quota info embedded in /v0/management/auth-files.
Changes:
- Add in-memory success/failed counters and a 20×10-minute ring buffer snapshot API to
sdk/cliproxy/auth.Auth. - Record request outcomes in
Manager.MarkResult()and preserve counters/history across auth updates/reloads. - Add
/v0/management/kiro-quota, a background quota refresher, and exposesuccess,failed,recent_requests, andkiro_quotain/v0/management/auth-files.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
sdk/cliproxy/auth/types.go |
Adds success/failed counters and recent-request ring buffer snapshot helpers. |
sdk/cliproxy/auth/conductor.go |
Records outcomes into the new counters/ring; preserves state on auth update. |
internal/api/handlers/management/auth_files.go |
Exposes health tracking fields and cached kiro_quota on auth listing. |
internal/api/handlers/management/kiro_quota.go |
Adds GET /v0/management/kiro-quota handler and response shaping. |
internal/api/handlers/management/kiro_quota_cache.go |
Implements a global in-process quota cache and background refresher. |
internal/api/server.go |
Registers the new route and starts the quota refresher. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+449
to
+451
| if kiroQuota := h.getKiroQuotaCached(auth); kiroQuota != nil { | ||
| entry["kiro_quota"] = kiroQuota | ||
| } |
Comment on lines
+24
to
+44
| // getKiroQuotaCached returns cached quota info for a Kiro auth entry. | ||
| func (h *Handler) getKiroQuotaCached(auth *coreauth.Auth) gin.H { | ||
| if auth == nil { | ||
| return nil | ||
| } | ||
| provider := strings.ToLower(strings.TrimSpace(auth.Provider)) | ||
| if provider != "kiro" { | ||
| return nil | ||
| } | ||
|
|
||
| kiroQuotaMu.RLock() | ||
| result, ok := kiroQuotaStore[auth.ID] | ||
| kiroQuotaMu.RUnlock() | ||
|
|
||
| if ok { | ||
| return result | ||
| } | ||
|
|
||
| // If not cached, try to fetch synchronously (first time only) | ||
| return h.fetchAndCacheKiroQuota(auth) | ||
| } |
Comment on lines
+61
to
+67
| ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) | ||
| defer cancel() | ||
|
|
||
| usage, err := checker.CheckUsage(ctx, tokenData) | ||
| if err != nil { | ||
| log.WithError(err).Debugf("kiro quota fetch failed for %s", auth.ID) | ||
| return nil |
| "resource_type": bd.ResourceType, | ||
| "used": bd.CurrentUsageWithPrecision, | ||
| "limit": bd.UsageLimitWithPrecision, | ||
| "remaining": bd.UsageLimitWithPrecision - bd.CurrentUsageWithPrecision, |
Comment on lines
+70
to
+75
| result := buildKiroQuotaEntry(usage) | ||
|
|
||
| kiroQuotaMu.Lock() | ||
| kiroQuotaStore[auth.ID] = result | ||
| kiroQuotaMu.Unlock() | ||
|
|
| usage, err := checker.CheckUsage(ctx, tokenData) | ||
| if err != nil { | ||
| log.WithError(err).Debug("kiro quota request failed") | ||
| c.JSON(http.StatusBadGateway, gin.H{"error": "kiro quota request failed: " + err.Error()}) |
Comment on lines
+72
to
+78
| // Build enriched response | ||
| response := gin.H{ | ||
| "usage": usage, | ||
| "quota_status": buildKiroQuotaStatus(usage), | ||
| "auth_index": auth.Index, | ||
| "auth_name": auth.FileName, | ||
| } |
Comment on lines
+634
to
+636
| start := time.Unix(bucketID*recentRequestBucketSeconds, 0).In(time.Local) | ||
| end := start.Add(time.Duration(recentRequestBucketSeconds) * time.Second) | ||
| return start.Format("15:04") + "-" + end.Format("15:04") |
Comment on lines
1979
to
+1988
| m.mu.Lock() | ||
| if auth, ok := m.auths[result.AuthID]; ok && auth != nil { | ||
| now := time.Now() | ||
|
|
||
| auth.recordRecentRequest(now, result.Success) | ||
| if result.Success { | ||
| auth.Success++ | ||
| } else { | ||
| auth.Failed++ | ||
| } |
Comment on lines
+35
to
+81
| func (h *Handler) GetKiroQuota(c *gin.Context) { | ||
| authIndex := strings.TrimSpace(c.Query("auth_index")) | ||
| if authIndex == "" { | ||
| authIndex = strings.TrimSpace(c.Query("authIndex")) | ||
| } | ||
| if authIndex == "" { | ||
| authIndex = strings.TrimSpace(c.Query("AuthIndex")) | ||
| } | ||
|
|
||
| auth := h.findKiroAuth(authIndex) | ||
| if auth == nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"error": "no kiro credential found"}) | ||
| return | ||
| } | ||
|
|
||
| // Extract token data from auth metadata | ||
| tokenData := extractKiroTokenData(auth) | ||
| if tokenData == nil || tokenData.AccessToken == "" { | ||
| c.JSON(http.StatusBadRequest, gin.H{"error": "kiro access token not available (token may need refresh)"}) | ||
| return | ||
| } | ||
|
|
||
| // Create usage checker with proxy-aware HTTP client | ||
| checker := kiro.NewUsageCheckerWithClient( | ||
| util.SetProxy(&h.cfg.SDKConfig, &http.Client{Timeout: 30 * time.Second}), | ||
| ) | ||
|
|
||
| ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second) | ||
| defer cancel() | ||
|
|
||
| usage, err := checker.CheckUsage(ctx, tokenData) | ||
| if err != nil { | ||
| log.WithError(err).Debug("kiro quota request failed") | ||
| c.JSON(http.StatusBadGateway, gin.H{"error": "kiro quota request failed: " + err.Error()}) | ||
| return | ||
| } | ||
|
|
||
| // Build enriched response | ||
| response := gin.H{ | ||
| "usage": usage, | ||
| "quota_status": buildKiroQuotaStatus(usage), | ||
| "auth_index": auth.Index, | ||
| "auth_name": auth.FileName, | ||
| } | ||
|
|
||
| c.JSON(http.StatusOK, response) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds two features to the management API:
1. Auth Health Status Tracking (recent_requests)
Resolves #23
Per-auth request success/failure tracking via a 20-bucket ring buffer (10-minute intervals, 200-minute sliding window). The
/v0/management/auth-filesendpoint now returnssuccess,failed, andrecent_requestsfields for each auth entry, enabling the management panel to render health status indicators (red/green/yellow bars).Before: Kiro and other auth entries had no health status data in the API response.
After: Each auth entry includes real-time request tracking that the panel can use to display health bars.
2. Kiro Quota Query
GET /v0/management/kiro-quota?auth_index=<INDEX>: Returns usage breakdown, remaining quota, usage percentage, subscription info, and next reset time.kiro_quotafield in/v0/management/auth-files: Each Kiro auth entry now includes cached quota info (plan, used, limit, remaining, percentage).Files Changed
sdk/cliproxy/auth/types.gosdk/cliproxy/auth/conductor.gointernal/api/handlers/management/auth_files.gointernal/api/handlers/management/kiro_quota.gointernal/api/handlers/management/kiro_quota_cache.gointernal/api/server.goTesting
go test ./...)