feat(antigravity): 增强网关功能和 thinking 块处理

主要改进:
- 优化 thinking blocks 过滤策略,支持 Auto 模式降级
- 将无效 thinking block 内容转为普通 text
- 保留单个空白 text block,不过滤
- 重构配额刷新机制,统一与 Claude 一致
- 支持 cachedContentTokenCount 映射到 cache_read_input_tokens
- Haiku 模型映射到 Sonnet
- 添加 /antigravity/v1/models 端点支持
- countTokens 端点直接返回空值
This commit is contained in:
ianshaw
2026-01-03 06:29:02 -08:00
parent df1ef3deb6
commit 26438f7232
15 changed files with 463 additions and 358 deletions

View File

@@ -1,5 +1,3 @@
// Package handler provides HTTP request handlers for the API gateway.
// It handles authentication, request routing, concurrency control, and billing validation.
package handler
import (
@@ -13,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"
@@ -29,7 +28,6 @@ type GatewayHandler struct {
userService *service.UserService
billingCacheService *service.BillingCacheService
concurrencyHelper *ConcurrencyHelper
opsService *service.OpsService
}
// NewGatewayHandler creates a new GatewayHandler
@@ -40,7 +38,6 @@ func NewGatewayHandler(
userService *service.UserService,
concurrencyService *service.ConcurrencyService,
billingCacheService *service.BillingCacheService,
opsService *service.OpsService,
) *GatewayHandler {
return &GatewayHandler{
gatewayService: gatewayService,
@@ -49,15 +46,14 @@ func NewGatewayHandler(
userService: userService,
billingCacheService: billingCacheService,
concurrencyHelper: NewConcurrencyHelper(concurrencyService, SSEPingFormatClaude),
opsService: opsService,
}
}
// Messages handles Claude API compatible messages endpoint
// POST /v1/messages
func (h *GatewayHandler) Messages(c *gin.Context) {
// 从context获取apiKey和userAPIKeyAuth中间件已设置
apiKey, ok := middleware2.GetAPIKeyFromContext(c)
// 从context获取apiKey和userApiKeyAuth中间件已设置
apiKey, ok := middleware2.GetApiKeyFromContext(c)
if !ok {
h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key")
return
@@ -92,7 +88,6 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
}
reqModel := parsedReq.Model
reqStream := parsedReq.Stream
setOpsRequestContext(c, reqModel, reqStream)
// 验证 model 必填
if reqModel == "" {
@@ -264,7 +259,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
defer cancel()
if err := h.gatewayService.RecordUsage(ctx, &service.RecordUsageInput{
Result: result,
APIKey: apiKey,
ApiKey: apiKey,
User: apiKey.User,
Account: usedAccount,
Subscription: subscription,
@@ -388,7 +383,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
defer cancel()
if err := h.gatewayService.RecordUsage(ctx, &service.RecordUsageInput{
Result: result,
APIKey: apiKey,
ApiKey: apiKey,
User: apiKey.User,
Account: usedAccount,
Subscription: subscription,
@@ -405,7 +400,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
// Returns models based on account configurations (model_mapping whitelist)
// Falls back to default models if no whitelist is configured
func (h *GatewayHandler) Models(c *gin.Context) {
apiKey, _ := middleware2.GetAPIKeyFromContext(c)
apiKey, _ := middleware2.GetApiKeyFromContext(c)
var groupID *int64
var platform string
@@ -451,10 +446,19 @@ 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) {
apiKey, ok := middleware2.GetAPIKeyFromContext(c)
apiKey, ok := middleware2.GetApiKeyFromContext(c)
if !ok {
h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key")
return
@@ -579,7 +583,6 @@ func (h *GatewayHandler) mapUpstreamError(statusCode int) (int, string, string)
// handleStreamingAwareError handles errors that may occur after streaming has started
func (h *GatewayHandler) handleStreamingAwareError(c *gin.Context, status int, errType, message string, streamStarted bool) {
if streamStarted {
recordOpsError(c, h.opsService, status, errType, message, "")
// Stream already started, send error as SSE event then close
flusher, ok := c.Writer.(http.Flusher)
if ok {
@@ -611,7 +614,6 @@ func (h *GatewayHandler) handleStreamingAwareError(c *gin.Context, status int, e
// errorResponse 返回Claude API格式的错误响应
func (h *GatewayHandler) errorResponse(c *gin.Context, status int, errType, message string) {
recordOpsError(c, h.opsService, status, errType, message, "")
c.JSON(status, gin.H{
"type": "error",
"error": gin.H{
@@ -625,8 +627,8 @@ func (h *GatewayHandler) errorResponse(c *gin.Context, status int, errType, mess
// POST /v1/messages/count_tokens
// 特点:校验订阅/余额,但不计算并发、不记录使用量
func (h *GatewayHandler) CountTokens(c *gin.Context) {
// 从context获取apiKey和userAPIKeyAuth中间件已设置
apiKey, ok := middleware2.GetAPIKeyFromContext(c)
// 从context获取apiKey和userApiKeyAuth中间件已设置
apiKey, ok := middleware2.GetApiKeyFromContext(c)
if !ok {
h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key")
return