• IanShaw's avatar
    Fix/multiple issues (#24) · 7fdc2b2d
    IanShaw authored
    * fix(gemini): 修复 google_one OAuth 配置和 scopes 问题
    
    - 修复 google_one 类型在 ExchangeCode 和 RefreshToken 中使用内置客户端
    - 添加 DefaultGoogleOneScopes,包含 generative-language 和 drive.readonly 权限
    - 在 EffectiveOAuthConfig 中为 google_one 类型使用专门的 scopes
    - 将 docker-compose.override.yml 重命名为 .example 并添加到 .gitignore
    - 完善 docker-compose.override.yml.example 示例文档
    
    解决问题:
    1. google_one OAuth 授权后 API 调用返回 403 权限不足
    2. 缺少访问 Gemini API 所需的 generative-language scope
    3. 缺少获取 Drive 存储配额所需的 drive.readonly scope
    
    * fix(antigravity): 完全跳过 Claude 模型的所有 thinking 块
    
    问题分析:
    - 当前代码尝试保留有 signature 的 thinking 块
    - 但 Vertex AI 的 signature 是完整性令牌,无法在本地验证
    - 导致 400 错误:Invalid signature in thinking block
    
    根本原因:
    1. thinking 功能已对非 Gemini 模型禁用 (isThinkingEnabled=false)
    2. Vertex AI 要求原样重放 (thinking, signature) 对或完全不发送
    3. 本地无法复制 Vertex 的加密验证逻辑
    
    修复方案:
    - 对 Claude 模型完全跳过所有 thinking 块(无论是否有 signature)
    - 保持 Gemini 模型使用 dummy signature 的行为不变
    - 更新测试用例以反映新的预期行为
    
    影响:
    - 消除 thinking 相关的 400 错误
    - 与现有的 thinking 禁用策略保持一致
    - 不影响 Gemini 模型的 thinking 功能
    
    测试:
    -  TestBuildParts_ThinkingBlockWithoutSignature 全部通过
    -  TestBuildTools_CustomTypeTools 全部通过
    
    参考:Codex review 建议
    
    * fix(gateway): 修复 count_tokens 端点 400 错误
    
    问题分析:
    - count_tokens 请求包含 thinking 块时返回 400 错误
    - 原因:thinking 块未被过滤,直接转发到上游 API
    - 上游 API 拒绝无效的 thinking signature
    
    根本原因:
    1. /v1/messages 请求通过 TransformClaudeToGemini 过滤 thinking 块
    2. count_tokens 请求绕过转换,直接转发原始请求体
    3. 导致包含无效 signature 的 thinking 块被发送到上游
    
    修复方案:
    - 创建 FilterThinkingBlocks 工具函数
    - 在 buildCountTokensRequest 中应用过滤(1 行修改)
    - 与 /v1/messages 行为保持一致
    
    实现细节:
    - FilterThinkingBlocks: 解析 JSON,过滤 thinking 块,重新序列化
    - 失败安全:解析/序列化失败时返回原始请求体
    - 性能优化:仅在发现 thinking 块时重新序列化
    
    测试:
    -  6 个单元测试全部通过
    -  覆盖正常过滤、无 thinking 块、无效 JSON 等场景
    -  现有测试不受影响
    
    影响:
    - 消除 count_tokens 的 400 错误
    - 不影响 Antigravity 账号(仍返回模拟响应)
    - 适用于所有账号类型(OAuth、API Key)
    
    文件修改:
    - backend/internal/service/gateway_request.go: +62 行(新函数)
    - backend/internal/service/gateway_service.go: +2 行(应用过滤)
    - backend/internal/service/gateway_request_test.go: +62 行(测试)
    
    * fix(gateway): 增强 thinking 块过滤逻辑
    
    基于 Codex 分析和建议的改进:
    
    问题分析:
    - 新错误:signature: Field required(signature 字段缺失)
    - 旧错误:Invalid signature(signature 存在但无效)
    - 两者都说明 thinking 块在请求中是危险的
    
    Codex 建议:
    - 保持 Option A:完全跳过所有 thinking 块
    - 原因:thinking 块应该是只输出的,除非有服务端来源证明
    - 在无状态代理中,无法安全区分上游来源 vs 客户端注入
    
    改进内容:
    
    1. 增强 FilterThinkingBlocks 函数
       - 过滤显式的 thinking 块:{"type":"thinking", ...}
       - 过滤无 type 的 thinking 对象:{"thinking": {...}}
       - 保留 tool_use 等其他类型块中的 thinking 字段
       - 修复:只在实际过滤时更新 content 数组
    
    2. 扩展过滤范围
       - 将 FilterThinkingBlocks 应用到 /v1/messages 主路径
       - 之前只应用于 count_tokens,现在两个端点都过滤
       - 防止所有端点的 thinking 相关 400 错误
    
    3. 改进测试
       - 新增:过滤无 type discriminator 的 thinking 块
       - 新增:不过滤 tool_use 中的 thinking 字段
       - 使用 containsThinkingBlock 辅助函数验证
    
    测试:
    -  8 个测试用例全部通过
    -  覆盖各种 thinking 块格式
    -  确保不误伤其他类型的块
    
    影响:
    - 消除 signature required 和 invalid signature 错误
    - 统一 /v1/messages 和 count_tokens 的行为
    - 更健壮的 thinking 块检测逻辑
    
    参考:Codex review 和代码改进
    
    * refactor: 根据 Codex 审查建议进行代码优化
    
    基于 Codex 代码审查的 P1 和 P2 改进:
    
    P1 改进(重要问题):
    
    1. 优化日志输出
       - 移除 thinking 块跳过时的 log.Printf
       - 避免高频请求下的日志噪音
       - 添加注释说明可通过指标监控
    
    2. 清理遗留代码
       - 删除未使用的 isValidThoughtSignature 函数(27行)
       - 该函数在改为完全跳过 thinking 块后不再需要
    
    P2 改进(性能优化):
    
    3. 添加快速路径检查
       - 在 FilterThinkingBlocks 中添加 bytes.Contains 预检查
       - 如果请求体不包含 "thinking" 字符串,直接返回
       - 避免不必要的 JSON 解析,提升性能
    
    技术细节:
    - request_transformer.go: -27行(删除函数),+1行(优化注释)
    - gateway_request.go: +5行(快速路径 + bytes 导入)
    
    测试:
    -  TestBuildParts_ThinkingBlockWithoutSignature 全部通过
    -  TestFilterThinkingBlocks 全部通过(8个测试用例)
    
    影响:
    - 减少日志噪音
    - 提升性能(快速路径)
    - 代码更简洁(删除未使用代码)
    
    参考:Codex 代码审查建议
    
    * fix: 修复 golangci-lint 检查问题
    
    - 格式化 gateway_request_test.go
    - 使用 switch 语句替代 if-else 链(staticcheck QF1003)
    
    * fix(antigravity): 修复 thinking signature 处理并实现 Auto 模式降级
    
    问题分析:
    1. 原先代码错误地禁用了 Claude via Vertex 的 thinkingConfig
    2. 历史 thinking 块的 signature 被完全跳过,导致验证失败
    3. 跨模型混用时 dummy signature 会导致 400 错误
    
    修复内容:
    
    **request_transformer.go**:
    - 删除第 38-43 行的错误逻辑(禁用 thinkingConfig)
    - 引入 thoughtSignatureMode(Preserve/Dummy)策略
    - Claude 模式:透传真实 signature,过滤空/dummy
    - Gemini 模式:使用 dummy signature
    - 支持 signature-only thinking 块
    - tool_use 的 signature 也透传
    
    **antigravity_gateway_service.go**:
    - 新增 isSignatureRelatedError() 检测 signature 相关错误
    - 新增 stripThinkingFromClaudeRequest() 移除 thinking 块
    - 实现 Auto 模式:检测 400 + signature 关键词时自动降级重试
    - 重试时完全移除 thinking 配置和消息中的 thinking 块
    - 最多重试一次,避免循环
    
    **测试**:
    - 更新并新增测试覆盖 Claude preserve/Gemini dummy 模式
    - 新增 tool_use signature 处理测试
    - 所有测试通过(6/6)
    
    影响:
    -  Claude via Vertex 可以正常使用 thinking 功能
    -  历史 signature 正确透传,避免验证失败
    -  跨模型混用时自动过滤无效 signature
    -  错误驱动降级,自动修复 signature 问题
    -  不影响纯 Claude API 和其他渠道
    
    参考:Codex 深度分析和实现建议
    
    * fix(lint): 修复 gofmt 格式问题
    
    * fix(antigravity): 修复 stripThinkingFromClaudeRequest 遗漏 untyped thinking blocks
    
    问题:
    - Codex 审查指出 stripThinkingFromClaudeRequest 只移除了 type="thinking" 的块
    - 没有处理没有 type 字段的 thinking 对象(如 {"thinking": "...", "signature": "..."})
    - 导致重试时仍包含无效 thinking 块,上游 400 错误持续
    
    修复:
    - 添加检查:跳过没有 type 但有 thinking 字段的块
    - 现在会移除两种格式:
      1. {"type": "thinking", "thinking": "...", "signature": "..."}
      2. {"thinking": "...", "signature": "..."}(untyped)
    
    测试:所有测试通过
    
    参考:Codex P1 审查意见
    7fdc2b2d
request_transformer_test.go 7.72 KB