From 95d09f60f81b715a979f4613e54c741dd11140a8 Mon Sep 17 00:00:00 2001
From: song
Date: Fri, 2 Jan 2026 10:21:05 +0800
Subject: [PATCH 01/19] =?UTF-8?q?feat(antigravity):=20=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=20models=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 02/19] =?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)
}
From 9d3ec9e627e164bf3020970026956246d6ce9442 Mon Sep 17 00:00:00 2001
From: shaw
Date: Fri, 2 Jan 2026 15:53:05 +0800
Subject: [PATCH 03/19] =?UTF-8?q?feat(keys):=20=E9=80=82=E9=85=8D=20Antigr?=
=?UTF-8?q?avity=20=E5=92=8C=20Gemini=20=E5=B9=B3=E5=8F=B0=E7=9A=84?=
=?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=95=99=E7=A8=8B=E4=B8=8E=20CCS=20=E5=AF=BC?=
=?UTF-8?q?=E5=85=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- UseKeyModal: 添加 Antigravity 两级 Tab (Claude Code / Gemini CLI)
- UseKeyModal: 添加 Gemini 平台的 Gemini CLI 教程
- UseKeyModal: Antigravity 平台统一使用 /antigravity 后缀
- KeysView: CCS 导入支持 Antigravity (询问客户端) / Gemini / OpenAI
- i18n: 添加相关中英文翻译
---
frontend/src/components/keys/UseKeyModal.vue | 185 ++++++++++++++++---
frontend/src/i18n/locales/en.ts | 22 ++-
frontend/src/i18n/locales/zh.ts | 22 ++-
frontend/src/views/user/KeysView.vue | 108 ++++++++++-
4 files changed, 307 insertions(+), 30 deletions(-)
diff --git a/frontend/src/components/keys/UseKeyModal.vue b/frontend/src/components/keys/UseKeyModal.vue
index 9414523d..7db67b96 100644
--- a/frontend/src/components/keys/UseKeyModal.vue
+++ b/frontend/src/components/keys/UseKeyModal.vue
@@ -28,7 +28,29 @@
{{ platformDescription }}
-
+
+
+
+
+
+