-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
feat(temporal): anti-drift injection for all provider requests #2574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
71a6b44
115cb5f
50ed89f
efb9735
e8ed002
8fb9745
956ce7f
33f0a78
1124bcd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ package management | |
| import ( | ||
| "net/http" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/gin-gonic/gin" | ||
| "github.com/router-for-me/CLIProxyAPI/v6/internal/registry" | ||
|
|
@@ -31,3 +32,93 @@ func (h *Handler) GetStaticModelDefinitions(c *gin.Context) { | |
| "models": models, | ||
| }) | ||
| } | ||
|
|
||
| // GetModelsHealth returns comprehensive health information for all registered models. | ||
| func (h *Handler) GetModelsHealth(c *gin.Context) { | ||
| globalRegistry := registry.GetGlobalRegistry() | ||
|
|
||
| // Get ALL registered models including suspended/unhealthy for full operator visibility | ||
| models := globalRegistry.GetAllRegisteredModels("openai") | ||
| // Build enhanced model health with suspension and provider info | ||
| enhancedModels := make([]map[string]any, 0, len(models)) | ||
| for _, model := range models { | ||
| modelID, _ := model["id"].(string) | ||
| if modelID == "" { | ||
| continue | ||
| } | ||
| // Get health details for this model | ||
| providers, suspendedClients, count := globalRegistry.GetModelHealthDetails(modelID) | ||
| // Build suspension summary | ||
| suspensionSummary := make(map[string]any) | ||
| if len(suspendedClients) > 0 { | ||
| suspensionSummary["count"] = len(suspendedClients) | ||
| suspensionSummary["clients"] = suspendedClients | ||
| // Extract unique reasons | ||
| reasons := make(map[string]bool) | ||
| for _, reason := range suspendedClients { | ||
| if reason == "" { | ||
| reasons["unknown"] = true | ||
| } else { | ||
| reasons[strings.ToLower(reason)] = true | ||
| } | ||
| } | ||
| reasonList := make([]string, 0, len(reasons)) | ||
| for reason := range reasons { | ||
| reasonList = append(reasonList, reason) | ||
| } | ||
| suspensionSummary["reasons"] = reasonList | ||
| } else { | ||
| suspensionSummary["count"] = 0 | ||
| suspensionSummary["clients"] = map[string]string{} | ||
| suspensionSummary["reasons"] = []string{} | ||
| } | ||
|
|
||
| // Build provider list | ||
| providerList := make([]string, 0, len(providers)) | ||
| for provider := range providers { | ||
| providerList = append(providerList, provider) | ||
| } | ||
| // Create enhanced model entry | ||
| enhancedModel := make(map[string]any) | ||
| for k, v := range model { | ||
| enhancedModel[k] = v | ||
| } | ||
| enhancedModel["total_clients"] = count | ||
| enhancedModel["providers"] = providerList | ||
| enhancedModel["provider_counts"] = providers | ||
| enhancedModel["suspension"] = suspensionSummary | ||
| enhancedModels = append(enhancedModels, enhancedModel) | ||
| } | ||
| // Build the sources map indicating where context_length came from | ||
| sources := registry.BuildModelSources(globalRegistry) | ||
| // Get last refresh timestamp from OpenRouter enrichment | ||
| lastRefresh := registry.GetOpenRouterLastRefresh() | ||
| lastRefreshStr := "" | ||
| if !lastRefresh.IsZero() { | ||
| lastRefreshStr = lastRefresh.Format(time.RFC3339) | ||
| } | ||
| response := gin.H{ | ||
| "models": enhancedModels, | ||
| "sources": sources, | ||
| "last_refresh": lastRefreshStr, | ||
| "refresh_interval": "24h", | ||
| } | ||
| c.JSON(http.StatusOK, response) | ||
| } | ||
|
|
||
| // RefreshModels triggers an immediate refresh of model metadata from OpenRouter and the enrichment cache. | ||
| // This re-fetches context_length from OpenRouter's public /api/v1/models endpoint and enriches registered models that lack this data. | ||
| func (h *Handler) RefreshModels(c *gin.Context) { | ||
| count := registry.TriggerOpenRouterRefresh(c.Request.Context()) | ||
| if count == 0 { | ||
| c.JSON(http.StatusBadRequest, gin.H{"error": "no models registered"}) | ||
| return | ||
| } | ||
| lastRefresh := registry.GetOpenRouterLastRefresh() | ||
| c.JSON(http.StatusOK, gin.H{ | ||
| "status": "refreshed", | ||
| "enriched_count": count, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| "last_refresh": lastRefresh.Format(time.RFC3339), | ||
| "total_models": len(registry.GetGlobalRegistry().GetAvailableModels("openai")), | ||
| }) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change introduces calls to
registry.BuildModelSources,registry.GetOpenRouterLastRefresh,registry.TriggerOpenRouterRefresh, andregistry.StartOpenRouterEnrichment, but no corresponding definitions are added in theinternal/registrypackage. That leaves these references unresolved at build time, so server/management packages cannot compile until the symbols are implemented (or the calls are removed).Useful? React with 👍 / 👎.