feat(antigravity): comprehensive enhancements - model mapping, rate limiting, scheduling & ops

Key changes:
- Upgrade model mapping: Opus 4.5 → Opus 4.6-thinking with precise matching
- Unified rate limiting: scope-level → model-level with Redis snapshot sync
- Load-balanced scheduling by call count with smart retry mechanism
- Force cache billing support
- Model identity injection in prompts with leak prevention
- Thinking mode auto-handling (max_tokens/budget_tokens fix)
- Frontend: whitelist mode toggle, model mapping validation, status indicators
- Gemini session fallback with Redis Trie O(L) matching
- Ops: enhanced concurrency monitoring, account availability, retry logic
- Migration scripts: 049-051 for model mapping unification
This commit is contained in:
erio
2026-02-07 12:31:10 +08:00
parent e617b45ba3
commit 5e98445b22
73 changed files with 8553 additions and 1926 deletions

View File

@@ -3,9 +3,12 @@ package service
import (
"encoding/json"
"sort"
"strconv"
"strings"
"time"
"github.com/Wei-Shaw/sub2api/internal/domain"
)
type Account struct {
@@ -347,10 +350,18 @@ func parseTempUnschedInt(value any) int {
func (a *Account) GetModelMapping() map[string]string {
if a.Credentials == nil {
// Antigravity 平台使用默认映射
if a.Platform == domain.PlatformAntigravity {
return domain.DefaultAntigravityModelMapping
}
return nil
}
raw, ok := a.Credentials["model_mapping"]
if !ok || raw == nil {
// Antigravity 平台使用默认映射
if a.Platform == domain.PlatformAntigravity {
return domain.DefaultAntigravityModelMapping
}
return nil
}
if m, ok := raw.(map[string]any); ok {
@@ -364,27 +375,46 @@ func (a *Account) GetModelMapping() map[string]string {
return result
}
}
// Antigravity 平台使用默认映射
if a.Platform == domain.PlatformAntigravity {
return domain.DefaultAntigravityModelMapping
}
return nil
}
// IsModelSupported 检查模型是否在 model_mapping 中(支持通配符)
// 如果未配置 mapping返回 true允许所有模型
func (a *Account) IsModelSupported(requestedModel string) bool {
mapping := a.GetModelMapping()
if len(mapping) == 0 {
return true // 无映射 = 允许所有
}
// 精确匹配
if _, exists := mapping[requestedModel]; exists {
return true
}
_, exists := mapping[requestedModel]
return exists
// 通配符匹配
for pattern := range mapping {
if matchWildcard(pattern, requestedModel) {
return true
}
}
return false
}
// GetMappedModel 获取映射后的模型名(支持通配符,最长优先匹配)
// 如果未配置 mapping返回原始模型名
func (a *Account) GetMappedModel(requestedModel string) string {
mapping := a.GetModelMapping()
if len(mapping) == 0 {
return requestedModel
}
// 精确匹配优先
if mappedModel, exists := mapping[requestedModel]; exists {
return mappedModel
}
return requestedModel
// 通配符匹配(最长优先)
return matchWildcardMapping(mapping, requestedModel)
}
func (a *Account) GetBaseURL() string {
@@ -426,6 +456,53 @@ func (a *Account) GetClaudeUserID() string {
return ""
}
// matchAntigravityWildcard 通配符匹配(仅支持末尾 *
// 用于 model_mapping 的通配符匹配
func matchAntigravityWildcard(pattern, str string) bool {
if strings.HasSuffix(pattern, "*") {
prefix := pattern[:len(pattern)-1]
return strings.HasPrefix(str, prefix)
}
return pattern == str
}
// matchWildcard 通用通配符匹配(仅支持末尾 *
// 复用 Antigravity 的通配符逻辑,供其他平台使用
func matchWildcard(pattern, str string) bool {
return matchAntigravityWildcard(pattern, str)
}
// matchWildcardMapping 通配符映射匹配(最长优先)
// 如果没有匹配,返回原始字符串
func matchWildcardMapping(mapping map[string]string, requestedModel string) string {
// 收集所有匹配的 pattern按长度降序排序最长优先
type patternMatch struct {
pattern string
target string
}
var matches []patternMatch
for pattern, target := range mapping {
if matchWildcard(pattern, requestedModel) {
matches = append(matches, patternMatch{pattern, target})
}
}
if len(matches) == 0 {
return requestedModel // 无匹配,返回原始模型名
}
// 按 pattern 长度降序排序
sort.Slice(matches, func(i, j int) bool {
if len(matches[i].pattern) != len(matches[j].pattern) {
return len(matches[i].pattern) > len(matches[j].pattern)
}
return matches[i].pattern < matches[j].pattern
})
return matches[0].target
}
func (a *Account) IsCustomErrorCodesEnabled() bool {
if a.Type != AccountTypeAPIKey || a.Credentials == nil {
return false