fix: 修复代码审查报告中的4个关键问题
1. 资源管理冗余(ForwardGemini双重Close) - 错误分支读取body后立即关闭原始body,用内存副本重新包装 - defer添加nil guard,避免重复关闭 - fallback成功时显式关闭旧body,确保连接释放 2. Schema校验丢失(cleanJSONSchema移除字段无感知) - 新增schemaCleaningWarningsEnabled()支持环境变量控制 - 实现warnSchemaKeyRemovedOnce()在非release模式下告警 - 移除关键验证字段时输出warning,包含key和path 3. UI响应式风险(UsersView操作菜单硬编码定位) - 菜单改为先粗定位、渲染后测量、再clamp到视口内 - 添加max-height + overflow-auto,超出时可滚动 - 增强交互:点击其它位置/滚动/resize自动关闭或重新定位 4. 身份补丁干扰(TransformClaudeToGemini默认注入) - 新增TransformOptions + TransformClaudeToGeminiWithOptions - 系统设置新增enable_identity_patch、identity_patch_prompt - 完整打通handler/dto/service/frontend配置链路 - 默认保持启用,向后兼容现有行为 测试: - 后端单测全量通过:go test ./... - 前端类型检查通过:npm run typecheck
This commit is contained in:
@@ -255,6 +255,16 @@ func (s *AntigravityGatewayService) buildClaudeTestRequest(projectID, mappedMode
|
||||
return antigravity.TransformClaudeToGemini(claudeReq, projectID, mappedModel)
|
||||
}
|
||||
|
||||
func (s *AntigravityGatewayService) getClaudeTransformOptions(ctx context.Context) antigravity.TransformOptions {
|
||||
opts := antigravity.DefaultTransformOptions()
|
||||
if s.settingService == nil {
|
||||
return opts
|
||||
}
|
||||
opts.EnableIdentityPatch = s.settingService.IsIdentityPatchEnabled(ctx)
|
||||
opts.IdentityPatch = s.settingService.GetIdentityPatchPrompt(ctx)
|
||||
return opts
|
||||
}
|
||||
|
||||
// extractGeminiResponseText 从 Gemini 响应中提取文本
|
||||
func extractGeminiResponseText(respBody []byte) string {
|
||||
var resp map[string]any
|
||||
@@ -380,7 +390,7 @@ func (s *AntigravityGatewayService) Forward(ctx context.Context, c *gin.Context,
|
||||
}
|
||||
|
||||
// 转换 Claude 请求为 Gemini 格式
|
||||
geminiBody, err := antigravity.TransformClaudeToGemini(&claudeReq, projectID, mappedModel)
|
||||
geminiBody, err := antigravity.TransformClaudeToGeminiWithOptions(&claudeReq, projectID, mappedModel, s.getClaudeTransformOptions(ctx))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("transform request: %w", err)
|
||||
}
|
||||
@@ -466,7 +476,7 @@ func (s *AntigravityGatewayService) Forward(ctx context.Context, c *gin.Context,
|
||||
|
||||
log.Printf("Antigravity account %d: detected signature-related 400, retrying once (%s)", account.ID, stage.name)
|
||||
|
||||
retryGeminiBody, txErr := antigravity.TransformClaudeToGemini(&retryClaudeReq, projectID, mappedModel)
|
||||
retryGeminiBody, txErr := antigravity.TransformClaudeToGeminiWithOptions(&retryClaudeReq, projectID, mappedModel, s.getClaudeTransformOptions(ctx))
|
||||
if txErr != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -101,6 +101,10 @@ const (
|
||||
SettingKeyFallbackModelOpenAI = "fallback_model_openai"
|
||||
SettingKeyFallbackModelGemini = "fallback_model_gemini"
|
||||
SettingKeyFallbackModelAntigravity = "fallback_model_antigravity"
|
||||
|
||||
// Request identity patch (Claude -> Gemini systemInstruction injection)
|
||||
SettingKeyEnableIdentityPatch = "enable_identity_patch"
|
||||
SettingKeyIdentityPatchPrompt = "identity_patch_prompt"
|
||||
)
|
||||
|
||||
// AdminAPIKeyPrefix is the prefix for admin API keys (distinct from user "sk-" keys).
|
||||
|
||||
@@ -130,6 +130,10 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
|
||||
updates[SettingKeyFallbackModelGemini] = settings.FallbackModelGemini
|
||||
updates[SettingKeyFallbackModelAntigravity] = settings.FallbackModelAntigravity
|
||||
|
||||
// Identity patch configuration (Claude -> Gemini)
|
||||
updates[SettingKeyEnableIdentityPatch] = strconv.FormatBool(settings.EnableIdentityPatch)
|
||||
updates[SettingKeyIdentityPatchPrompt] = settings.IdentityPatchPrompt
|
||||
|
||||
return s.settingRepo.SetMultiple(ctx, updates)
|
||||
}
|
||||
|
||||
@@ -213,6 +217,9 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
||||
SettingKeyFallbackModelOpenAI: "gpt-4o",
|
||||
SettingKeyFallbackModelGemini: "gemini-2.5-pro",
|
||||
SettingKeyFallbackModelAntigravity: "gemini-2.5-pro",
|
||||
// Identity patch defaults
|
||||
SettingKeyEnableIdentityPatch: "true",
|
||||
SettingKeyIdentityPatchPrompt: "",
|
||||
}
|
||||
|
||||
return s.settingRepo.SetMultiple(ctx, defaults)
|
||||
@@ -269,6 +276,14 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
|
||||
result.FallbackModelGemini = s.getStringOrDefault(settings, SettingKeyFallbackModelGemini, "gemini-2.5-pro")
|
||||
result.FallbackModelAntigravity = s.getStringOrDefault(settings, SettingKeyFallbackModelAntigravity, "gemini-2.5-pro")
|
||||
|
||||
// Identity patch settings (default: enabled, to preserve existing behavior)
|
||||
if v, ok := settings[SettingKeyEnableIdentityPatch]; ok && v != "" {
|
||||
result.EnableIdentityPatch = v == "true"
|
||||
} else {
|
||||
result.EnableIdentityPatch = true
|
||||
}
|
||||
result.IdentityPatchPrompt = settings[SettingKeyIdentityPatchPrompt]
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -298,6 +313,25 @@ func (s *SettingService) GetTurnstileSecretKey(ctx context.Context) string {
|
||||
return value
|
||||
}
|
||||
|
||||
// IsIdentityPatchEnabled 检查是否启用身份补丁(Claude -> Gemini systemInstruction 注入)
|
||||
func (s *SettingService) IsIdentityPatchEnabled(ctx context.Context) bool {
|
||||
value, err := s.settingRepo.GetValue(ctx, SettingKeyEnableIdentityPatch)
|
||||
if err != nil {
|
||||
// 默认开启,保持兼容
|
||||
return true
|
||||
}
|
||||
return value == "true"
|
||||
}
|
||||
|
||||
// GetIdentityPatchPrompt 获取自定义身份补丁提示词(为空表示使用内置默认模板)
|
||||
func (s *SettingService) GetIdentityPatchPrompt(ctx context.Context) string {
|
||||
value, err := s.settingRepo.GetValue(ctx, SettingKeyIdentityPatchPrompt)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// GenerateAdminAPIKey 生成新的管理员 API Key
|
||||
func (s *SettingService) GenerateAdminAPIKey(ctx context.Context) (string, error) {
|
||||
// 生成 32 字节随机数 = 64 位十六进制字符
|
||||
|
||||
@@ -32,6 +32,10 @@ type SystemSettings struct {
|
||||
FallbackModelOpenAI string `json:"fallback_model_openai"`
|
||||
FallbackModelGemini string `json:"fallback_model_gemini"`
|
||||
FallbackModelAntigravity string `json:"fallback_model_antigravity"`
|
||||
|
||||
// Identity patch configuration (Claude -> Gemini)
|
||||
EnableIdentityPatch bool `json:"enable_identity_patch"`
|
||||
IdentityPatchPrompt string `json:"identity_patch_prompt"`
|
||||
}
|
||||
|
||||
type PublicSettings struct {
|
||||
|
||||
Reference in New Issue
Block a user