1. 28 Jan, 2026 2 commits
  2. 27 Jan, 2026 2 commits
  3. 26 Jan, 2026 3 commits
    • song's avatar
      feat(gemini): 为 Gemini 原生平台添加图片计费支持 · 0059a232
      song authored
      对齐 Antigravity 平台的图片计费逻辑:
      - 添加 extractImageSize() 方法提取图片尺寸
      - Forward() 和 ForwardNative() 返回 ImageCount/ImageSize
      - 支持分组自定义图片价格和倍率
      0059a232
    • ianshaw's avatar
      fix(ratelimit): 修复 OpenAI usage_limit_reached 错误的重置时间解析 · a55cfebd
      ianshaw authored
      - 问题:OpenAI 的 usage_limit_reached 错误(需 37 小时重置)被错误地设置为 5 分钟
      - 原因:handle429 只检查 Anthropic 响应头,没有解析 OpenAI 响应体中的 resets_in_seconds
      - 修复:新增 parseOpenAIRateLimitResetTime 函数解析 OpenAI 响应体
      - 影响:避免调度器不断尝试已达配额上限的账户
      a55cfebd
    • shaw's avatar
      feat(auth): 实现 TOTP 双因素认证功能 · 1245f07a
      shaw authored
      新增功能:
      - 支持 Google Authenticator 等应用进行 TOTP 二次验证
      - 用户可在个人设置中启用/禁用 2FA
      - 登录时支持 TOTP 验证流程
      - 管理后台可全局开关 TOTP 功能
      
      安全增强:
      - TOTP 密钥使用 AES-256-GCM 加密存储
      - 添加 TOTP_ENCRYPTION_KEY 配置项,必须手动配置才能启用功能
      - 防止服务重启导致加密密钥变更使用户无法登录
      - 验证失败次数限制,防止暴力破解
      
      配置说明:
      - Docker 部署:在 .env 中设置 TOTP_ENCRYPTION_KEY
      - 非 Docker 部署:在 config.yaml 中设置 totp.encryption_key
      - 生成密钥命令:openssl rand -hex 32
      1245f07a
  4. 25 Jan, 2026 3 commits
    • ianshaw's avatar
      feat(gemini): 支持 Gemini CLI 粘性会话与跨账号 thoughtSignature 清理 · 839975b0
      ianshaw authored
      ## 问题背景
      
      1. Gemini CLI 没有明确的会话标识(如 Claude Code 的 metadata.user_id)
      2. thoughtSignature 与具体上游账号强绑定,跨账号使用会导致 400 错误
      3. 粘性会话切换账号或 cache 丢失时,旧签名会导致请求失败
      
      ## 解决方案
      
      ### 1. Gemini CLI 会话标识提取
      
      - 从 `x-gemini-api-privileged-user-id` header 和请求体中的 tmp 目录哈希生成会话标识
      - 组合策略:SHA256(privileged-user-id + ":" + tmp_dir_hash)
      - 正则提取:`/\.gemini/tmp/([A-Fa-f0-9]{64})`
      
      ### 2. 跨账号 thoughtSignature 清理
      
      实现三种场景的智能清理:
      
      1. **Cache 命中 + 账号切换**
         - 粘性会话绑定的账号与当前选择的账号不同时清理
      
      2. **同一请求内 failover 切换**
         - 通过 sessionBoundAccountID 跟踪,检测重试时的账号切换
      
      3. **Gemini CLI + Cache 未命中 + 含签名**
         - 预防性清理,避免 cache 丢失后首次转发就 400
         - 仅对 Gemini CLI 请求且请求体包含 thoughtSignature 时触发
      
      ## 修改内容
      
      ### backend/internal/handler/gemini_v1beta_handler.go
      - 添加 `extractGeminiCLISessionHash` 函数提取 Gemini CLI 会话标识
      - 添加 `isGeminiCLIRequest` 函数识别 Gemini CLI 请求
      - 实现账号切换检测与 thoughtSignature 清理逻辑
      - 添加 `geminiCLITmpDirRegex` 正则表达式
      
      ### backend/internal/service/gateway_service.go
      - 添加 `GetCachedSessionAccountID` 方法查询粘性会话绑定的账号 ID
      
      ### backend/internal/service/gemini_native_signature_cleaner.go (新增)
      - 实现 `CleanGeminiNativeThoughtSignatures` 函数
      - 递归清理 JSON 中的所有 thoughtSignature 字段
      - 支持任意 JSON 顶层类型(object/array)
      
      ### backend/internal/handler/gemini_cli_session_test.go (新增)
      - 测试 Gemini CLI 会话哈希提取逻辑
      - 测试 tmp 目录正则匹配
      - 覆盖有/无 privileged-user-id 的场景
      
      ## 影响范围
      
      - 修复 Gemini CLI 多轮对话时账号切换导致的 400 错误
      - 提高粘性会话的稳定性和容错能力
      - 不影响其他客户端(Claude Code 等)的会话标识生成
      
      ## 测试
      
      - 单元测试:go test -tags=unit ./internal/handler -run TestExtractGeminiCLISessionHash
      - 单元测试:go test -tags=unit ./internal/handler -run TestGeminiCLITmpDirRegex
      - 编译验证:go build ./cmd/server
      839975b0
    • Gemini Wen's avatar
      fix(subscription): 修复订阅调整逻辑,已过期订阅从当前时间计算 · 9cdb0568
      Gemini Wen authored
      
      
      - 已过期订阅延长时,从当前时间开始增加天数
      - 已过期订阅不允许负向调整(缩短)
      - 未过期订阅保持原逻辑,从原过期时间增减
      Co-Authored-By: default avatarClaude Sonnet 4.5 <noreply@anthropic.com>
      9cdb0568
    • shaw's avatar
      fix(ratelimit): 修复 OpenAI 账号限流倒计时计算错误 · 74e05b83
      shaw authored
      - 解析 x-codex-* 响应头获取正确的重置时间
      - 7d 限制用尽时使用 codex_7d_reset_after_seconds
      - 提取 Normalize() 方法统一窗口规范化逻辑
      74e05b83
  5. 24 Jan, 2026 5 commits
    • Ubuntu's avatar
      fix(oauth): 为初始 OAuth 授权添加 LoadCodeAssist 重试机制 · 4ded9e7d
      Ubuntu authored
      
      
      问题:
      - 初始授权时 LoadCodeAssist 没有重试机制,失败后直接跳过
      - 导致账号创建时就可能缺失 project_id
      - 之后每次刷新都因为 missing_project_id 报错
      
      修复:
      - 统一使用 loadProjectIDWithRetry 方法(最多4次尝试)
      - 初始授权和token刷新使用相同的重试策略
      - 保留原注释说明部分账户可能没有 project_id
      Co-Authored-By: default avatarClaude Sonnet 4.5 <noreply@anthropic.com>
      4ded9e7d
    • Ubuntu's avatar
      fix(oauth): 彻底修复 project_id 丢失问题 · 716272a1
      Ubuntu authored
      
      
      根本原因:
      - BuildAccountCredentials 只在 project_id 非空时才添加该字段
      - LoadCodeAssist 失败时返回空字符串 → 新 credentials 不包含 project_id 键
      - 普通合并逻辑只保留新 credentials 中不存在的键,无法覆盖空值
      
      解决方案:
      1. 在合并后特殊处理 project_id:如果新值为空但旧值非空,保留旧值
      2. LoadCodeAssist 失败不再返回错误,只记录警告
      3. Token 刷新成功(access_token 已更新)就不应标记账户为 error
      
      改进效果:
      - 即使 LoadCodeAssist 连续失败,已有的 project_id 也不会丢失
      - 避免因临时网络问题将账户误标记为不可用
      - 允许在下次刷新时自动重试获取 project_id
      Co-Authored-By: default avatarClaude Sonnet 4.5 <noreply@anthropic.com>
      716272a1
    • shaw's avatar
      feat(auth): 密码重置邮件队列化与限流优化 · 9cc83525
      shaw authored
      - 邮件发送改为异步队列处理,避免并发导致发送失败
      - 新增 Email 维度限流(30秒冷却期),防止邮件轰炸
      - Token 验证使用常量时间比较,防止时序攻击
      - 重构代码消除冗余,提取公共验证逻辑
      9cc83525
    • shaw's avatar
      feat(subscription): 订阅过期状态自动更新与服务端排序 · b0aa2354
      shaw authored
      - 新增 SubscriptionExpiryService 定时任务,每分钟更新过期订阅状态
      - 订阅列表支持服务端排序(按过期时间、状态、创建时间)
      - 实时显示正确的过期状态,无需等待定时任务
      - 允许对已过期订阅进行续期操作
      - DataTable 组件支持 serverSideSort 模式
      b0aa2354
    • Ubuntu's avatar
      fix(oauth): 修复 OAuth 令牌刷新时 missing_project_id 误报问题 · ffaa6c4a
      Ubuntu authored
      
      
      问题描述:
      在网络波动环境下,LoadCodeAssist 临时失败会被错误地标记为
      "missing_project_id" 不可重试错误,导致账户被禁用。但实际上
      账户配置正确,手动刷新后即可恢复。
      
      解决方案:
      1. 为 LoadCodeAssist 增加重试机制(最多4次,指数退避)
      2. 区分真正的配置缺失和临时网络故障:
         - 如果之前有 project_id,本次获取失败只保留旧值,不报错
         - 只有从未获取过 project_id 且本次也失败时,才标记为缺失
      3. 优化错误判断逻辑,避免误报
      
      改进效果:
      - 提高在复杂网络环境(如家宽代理)下的鲁棒性
      - 减少因临时网络波动导致的服务中断
      - 保持真正配置错误的检测能力
      Co-Authored-By: default avatarClaude Sonnet 4.5 <noreply@anthropic.com>
      ffaa6c4a
  6. 23 Jan, 2026 4 commits
    • lynoot's avatar
      fix(gateway): aggregate all text chunks in non-streaming Gemini responses · 909b8a8f
      lynoot authored
      Previously, collectGeminiSSE() only returned the last chunk received
      from the upstream streaming response when converting to non-streaming.
      This caused incomplete responses where only the final text fragment
      was returned to clients.
      
      For example, a request asking to "count from 1 to 10" would only
      return "\n" (the last chunk) instead of "1\n2\n3\n...\n10\n".
      
      This was especially problematic for JSON structured output where
      the opening brace "{" from the first chunk was lost, resulting
      in invalid JSON like: colors": ["red", "blue"]}
      
      The fix:
      - Collect all text parts from each SSE chunk into a slice
      - Merge all collected text parts into the final response
      - Reuse the same pattern as handleGeminiStreamToNonStreaming
        in antigravity_gateway_service.go
      
      Fixes: non-streaming responses returning incomplete text
      Fixes: structured output (JSON schema) returning invalid JSON
      909b8a8f
    • shaw's avatar
      feat: 保存并显示OAuth账号邮箱地址 · f9ab1daa
      shaw authored
      f9ab1daa
    • shaw's avatar
      fix(test): 修复测试中引用不存在的函数名 · d27b8474
      shaw authored
      测试文件引用了 IsTokenVersionStale 函数,但实际函数名为 CheckTokenVersion,导致 CI 构建失败
      d27b8474
    • shaw's avatar
      fix(token-cache): 版本过时时使用最新token而非旧token · dac6bc22
      shaw authored
      上次修复(2665230a)只阻止了写入缓存,但仍返回旧token导致403。
      现在版本过时时直接使用DB中的最新token返回。
      
      - 重构 IsTokenVersionStale 为 CheckTokenVersion,返回最新account
      - 消除重复DB查询,复用版本检查时已获取的account
      dac6bc22
  7. 22 Jan, 2026 3 commits
    • shaw's avatar
      fix(token-cache): 修复异步刷新与请求线程的缓存竞态条件 · 2665230a
      shaw authored
      - 新增 _token_version 版本号机制,防止过期 token 污染缓存
      - TokenRefreshService 刷新成功后写入版本号并清除缓存
      - TokenProvider 写入缓存前检查版本,过时则跳过
      - ClearError 时同步清除 token 缓存
      2665230a
    • 0xff26b9a8's avatar
      style: gofmt antigravity_gateway_service.go · 4f0c2b79
      0xff26b9a8 authored
      4f0c2b79
    • 0xff26b9a8's avatar
      fix(antigravity): 修复非流式 Claude To Antigravity 响应内容为空的问题 · e756064c
      0xff26b9a8 authored
      - 修复 TransformGeminiToClaude 的 JSON 解析逻辑,当 V1InternalResponse
        解析成功但 candidates 为空时,尝试直接解析为 GeminiResponse 格式
      - 修复 handleClaudeStreamToNonStreaming 收集流式响应的逻辑,累积所有
        chunks 的内容而不是只保留最后一个(最后一个 chunk 通常 text 为空)
      - 新增 mergeCollectedPartsToResponse 函数,合并所有类型的 parts
        (text、thinking、functionCall、inlineData),保持原始顺序
      - 连续的普通 text parts 合并为一个,thinking/functionCall/inlineData 保持原样
      e756064c
  8. 20 Jan, 2026 5 commits
  9. 19 Jan, 2026 10 commits
  10. 18 Jan, 2026 3 commits