From 95d09f60f81b715a979f4613e54c741dd11140a8 Mon Sep 17 00:00:00 2001 From: song Date: Fri, 2 Jan 2026 10:21:05 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(antigravity):=20=E6=B7=BB=E5=8A=A0=20m?= =?UTF-8?q?odels=20=E7=AB=AF=E7=82=B9=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /antigravity/models: 返回全部模型(Claude + Gemini) - /antigravity/v1/models: 返回全部模型(Claude API 格式) - /antigravity/v1beta/models: 仅返回 Gemini 模型(v1beta 格式) 统一管理 antigravity 模型定义,避免重复代码 --- backend/internal/handler/gateway_handler.go | 23 ++++- .../internal/handler/gemini_v1beta_handler.go | 9 +- .../internal/pkg/antigravity/claude_types.go | 88 +++++++++++++++++++ backend/internal/server/routes/gateway.go | 3 + 4 files changed, 118 insertions(+), 5 deletions(-) diff --git a/backend/internal/handler/gateway_handler.go b/backend/internal/handler/gateway_handler.go index a2f833ff..057cb2ca 100644 --- a/backend/internal/handler/gateway_handler.go +++ b/backend/internal/handler/gateway_handler.go @@ -11,6 +11,7 @@ import ( "strings" "time" + "github.com/Wei-Shaw/sub2api/internal/pkg/antigravity" "github.com/Wei-Shaw/sub2api/internal/pkg/claude" "github.com/Wei-Shaw/sub2api/internal/pkg/openai" middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware" @@ -308,10 +309,21 @@ func (h *GatewayHandler) Messages(c *gin.Context) { // Models handles listing available models // GET /v1/models -// Returns different model lists based on the API key's group platform +// Returns different model lists based on the API key's group platform or forced platform func (h *GatewayHandler) Models(c *gin.Context) { apiKey, _ := middleware2.GetApiKeyFromContext(c) + // 优先检查强制平台(/antigravity 路由) + if forcePlatform, ok := middleware2.GetForcePlatformFromContext(c); ok { + if forcePlatform == service.PlatformAntigravity { + c.JSON(http.StatusOK, gin.H{ + "object": "list", + "data": antigravity.DefaultModels(), + }) + return + } + } + // Return OpenAI models for OpenAI platform groups if apiKey != nil && apiKey.Group != nil && apiKey.Group.Platform == "openai" { c.JSON(http.StatusOK, gin.H{ @@ -328,6 +340,15 @@ func (h *GatewayHandler) Models(c *gin.Context) { }) } +// AntigravityModels 返回 Antigravity 支持的全部模型 +// GET /antigravity/models +func (h *GatewayHandler) AntigravityModels(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{ + "object": "list", + "data": antigravity.DefaultModels(), + }) +} + // Usage handles getting account balance for CC Switch integration // GET /v1/usage func (h *GatewayHandler) Usage(c *gin.Context) { diff --git a/backend/internal/handler/gemini_v1beta_handler.go b/backend/internal/handler/gemini_v1beta_handler.go index 4e99e00d..e50f86aa 100644 --- a/backend/internal/handler/gemini_v1beta_handler.go +++ b/backend/internal/handler/gemini_v1beta_handler.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/Wei-Shaw/sub2api/internal/pkg/antigravity" "github.com/Wei-Shaw/sub2api/internal/pkg/gemini" "github.com/Wei-Shaw/sub2api/internal/pkg/googleapi" "github.com/Wei-Shaw/sub2api/internal/server/middleware" @@ -32,9 +33,9 @@ func (h *GatewayHandler) GeminiV1BetaListModels(c *gin.Context) { return } - // 强制 antigravity 模式:直接返回静态模型列表 + // 强制 antigravity 模式:返回 antigravity 支持的模型列表 if forcePlatform == service.PlatformAntigravity { - c.JSON(http.StatusOK, gemini.FallbackModelsList()) + c.JSON(http.StatusOK, antigravity.FallbackGeminiModelsList()) return } @@ -84,9 +85,9 @@ func (h *GatewayHandler) GeminiV1BetaGetModel(c *gin.Context) { return } - // 强制 antigravity 模式:直接返回静态模型信息 + // 强制 antigravity 模式:返回 antigravity 模型信息 if forcePlatform == service.PlatformAntigravity { - c.JSON(http.StatusOK, gemini.FallbackModel(modelName)) + c.JSON(http.StatusOK, antigravity.FallbackGeminiModel(modelName)) return } diff --git a/backend/internal/pkg/antigravity/claude_types.go b/backend/internal/pkg/antigravity/claude_types.go index 01b805cd..6baa7907 100644 --- a/backend/internal/pkg/antigravity/claude_types.go +++ b/backend/internal/pkg/antigravity/claude_types.go @@ -135,3 +135,91 @@ type ErrorDetail struct { Type string `json:"type"` Message string `json:"message"` } + +// modelDef Antigravity 模型定义(内部使用) +type modelDef struct { + ID string + DisplayName string + CreatedAt string // 仅 Claude API 格式使用 +} + +// Antigravity 支持的 Claude 模型 +var claudeModels = []modelDef{ + {ID: "claude-opus-4-5-thinking", DisplayName: "Claude Opus 4.5 Thinking", CreatedAt: "2025-11-01T00:00:00Z"}, + {ID: "claude-sonnet-4-5", DisplayName: "Claude Sonnet 4.5", CreatedAt: "2025-09-29T00:00:00Z"}, + {ID: "claude-sonnet-4-5-thinking", DisplayName: "Claude Sonnet 4.5 Thinking", CreatedAt: "2025-09-29T00:00:00Z"}, +} + +// Antigravity 支持的 Gemini 模型 +var geminiModels = []modelDef{ + {ID: "gemini-2.5-flash", DisplayName: "Gemini 2.5 Flash", CreatedAt: "2025-01-01T00:00:00Z"}, + {ID: "gemini-2.5-flash-lite", DisplayName: "Gemini 2.5 Flash Lite", CreatedAt: "2025-01-01T00:00:00Z"}, + {ID: "gemini-2.5-flash-thinking", DisplayName: "Gemini 2.5 Flash Thinking", CreatedAt: "2025-01-01T00:00:00Z"}, + {ID: "gemini-3-flash", DisplayName: "Gemini 3 Flash", CreatedAt: "2025-06-01T00:00:00Z"}, + {ID: "gemini-3-pro-low", DisplayName: "Gemini 3 Pro Low", CreatedAt: "2025-06-01T00:00:00Z"}, + {ID: "gemini-3-pro-high", DisplayName: "Gemini 3 Pro High", CreatedAt: "2025-06-01T00:00:00Z"}, + {ID: "gemini-3-pro-preview", DisplayName: "Gemini 3 Pro Preview", CreatedAt: "2025-06-01T00:00:00Z"}, + {ID: "gemini-3-pro-image", DisplayName: "Gemini 3 Pro Image", CreatedAt: "2025-06-01T00:00:00Z"}, +} + +// ========== Claude API 格式 (/v1/models) ========== + +// ClaudeModel Claude API 模型格式 +type ClaudeModel struct { + ID string `json:"id"` + Type string `json:"type"` + DisplayName string `json:"display_name"` + CreatedAt string `json:"created_at"` +} + +// DefaultModels 返回 Claude API 格式的模型列表(Claude + Gemini) +func DefaultModels() []ClaudeModel { + all := append(claudeModels, geminiModels...) + result := make([]ClaudeModel, len(all)) + for i, m := range all { + result[i] = ClaudeModel{ID: m.ID, Type: "model", DisplayName: m.DisplayName, CreatedAt: m.CreatedAt} + } + return result +} + +// ========== Gemini v1beta 格式 (/v1beta/models) ========== + +// GeminiModel Gemini v1beta 模型格式 +type GeminiModel struct { + Name string `json:"name"` + DisplayName string `json:"displayName,omitempty"` + SupportedGenerationMethods []string `json:"supportedGenerationMethods,omitempty"` +} + +// GeminiModelsListResponse Gemini v1beta 模型列表响应 +type GeminiModelsListResponse struct { + Models []GeminiModel `json:"models"` +} + +var defaultGeminiMethods = []string{"generateContent", "streamGenerateContent"} + +// DefaultGeminiModels 返回 Gemini v1beta 格式的模型列表(仅 Gemini 模型) +func DefaultGeminiModels() []GeminiModel { + result := make([]GeminiModel, len(geminiModels)) + for i, m := range geminiModels { + result[i] = GeminiModel{Name: "models/" + m.ID, DisplayName: m.DisplayName, SupportedGenerationMethods: defaultGeminiMethods} + } + return result +} + +// FallbackGeminiModelsList 返回 Gemini v1beta 格式的模型列表响应 +func FallbackGeminiModelsList() GeminiModelsListResponse { + return GeminiModelsListResponse{Models: DefaultGeminiModels()} +} + +// FallbackGeminiModel 返回单个模型信息(v1beta 格式) +func FallbackGeminiModel(model string) GeminiModel { + if model == "" { + return GeminiModel{Name: "models/unknown", SupportedGenerationMethods: defaultGeminiMethods} + } + name := model + if len(model) < 7 || model[:7] != "models/" { + name = "models/" + model + } + return GeminiModel{Name: name, SupportedGenerationMethods: defaultGeminiMethods} +} diff --git a/backend/internal/server/routes/gateway.go b/backend/internal/server/routes/gateway.go index 38df9225..4f1083b0 100644 --- a/backend/internal/server/routes/gateway.go +++ b/backend/internal/server/routes/gateway.go @@ -47,6 +47,9 @@ func RegisterGatewayRoutes( // OpenAI Responses API(不带v1前缀的别名) r.POST("/responses", bodyLimit, gin.HandlerFunc(apiKeyAuth), h.OpenAIGateway.Responses) + // Antigravity 模型列表 + r.GET("/antigravity/models", gin.HandlerFunc(apiKeyAuth), h.Gateway.AntigravityModels) + // Antigravity 专用路由(仅使用 antigravity 账户,不混合调度) antigravityV1 := r.Group("/antigravity/v1") antigravityV1.Use(bodyLimit) From f1fdb5d38f80f108fc781f12cc28373f75a9a2c3 Mon Sep 17 00:00:00 2001 From: song Date: Fri, 2 Jan 2026 10:32:20 +0800 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20/antigravity/v1/models=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E4=B8=93=E7=94=A8=20handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 不再复用 Models(),避免内部 ForcePlatform 判断 --- backend/internal/handler/gateway_handler.go | 11 ----------- backend/internal/server/routes/gateway.go | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/backend/internal/handler/gateway_handler.go b/backend/internal/handler/gateway_handler.go index 475bc38f..7eb7007e 100644 --- a/backend/internal/handler/gateway_handler.go +++ b/backend/internal/handler/gateway_handler.go @@ -402,17 +402,6 @@ func (h *GatewayHandler) Messages(c *gin.Context) { func (h *GatewayHandler) Models(c *gin.Context) { apiKey, _ := middleware2.GetApiKeyFromContext(c) - // 优先检查强制平台(/antigravity 路由) - if forcePlatform, ok := middleware2.GetForcePlatformFromContext(c); ok { - if forcePlatform == service.PlatformAntigravity { - c.JSON(http.StatusOK, gin.H{ - "object": "list", - "data": antigravity.DefaultModels(), - }) - return - } - } - var groupID *int64 var platform string diff --git a/backend/internal/server/routes/gateway.go b/backend/internal/server/routes/gateway.go index 4f1083b0..941f1ce9 100644 --- a/backend/internal/server/routes/gateway.go +++ b/backend/internal/server/routes/gateway.go @@ -58,7 +58,7 @@ func RegisterGatewayRoutes( { antigravityV1.POST("/messages", h.Gateway.Messages) antigravityV1.POST("/messages/count_tokens", h.Gateway.CountTokens) - antigravityV1.GET("/models", h.Gateway.Models) + antigravityV1.GET("/models", h.Gateway.AntigravityModels) antigravityV1.GET("/usage", h.Gateway.Usage) }