1. 27 Dec, 2025 5 commits
  2. 26 Dec, 2025 20 commits
    • IanShaw027's avatar
      feat(test): 添加 Gemini 双响应格式支持 · 2714be99
      IanShaw027 authored
      添加对两种 Gemini 响应格式的支持:
      - AI Studio: `{"candidates": [...]}`
      - Gemini CLI: `{"response": {"candidates": [...]}}`
      
      通过 unwrap 逻辑自动检测并适配两种格式,确保账号测试功能
      对所有 Gemini 账号类型都能正常工作。
      
      合并 PR #43 的剩余功能到 PR #37
      2714be99
    • IanShaw027's avatar
      fix(lint): 修复 gofmt 格式问题 · d8518180
      IanShaw027 authored
      修复 golangci-lint 检查失败的问题:
      - gemini_token_provider.go: 删除 import 后多余空行
      - gemini_token_refresher.go: 删除 import 后多余空行
      
      Fixes CI golangci-lint check for PR #37
      d8518180
    • IanShaw027's avatar
      refactor: 统一使用 mergeMap 函数提升代码一致性 · 576bf463
      IanShaw027 authored
      根据 Gemini CLI 代码审查建议:
      
      ## 修改内容
      - 将 Gemini OAuth 同步中的 `mergeJSONB` 调用替换为 `mergeMap`
      - 删除不再使用的 `mergeJSONB` 函数定义
      
      ## 原因
      - 其他平台(OpenAI、Anthropic)的账户同步都使用 `mergeMap`
      - `mergeJSONB` 是为旧的 `model.JSONB` 类型设计,与重构后的架构不一致
      - 统一函数命名提高代码可读性和可维护性
      
      ## 影响范围
      - backend/internal/service/crs_sync_service.go (4处替换)
      - backend/internal/service/account.go (删除 mergeJSONB 函数)
      
      ## 验证
      ✓ 编译通过
      ✓ 功能逻辑无变化(mergeMap 和 mergeJSONB 实现相同)
      576bf463
    • IanShaw027's avatar
      fix(backend): 适配重构后的架构修复 Gemini OAuth 集成 · 9db52838
      IanShaw027 authored
      ## 主要修改
      
      1. **移除 model 包引用**
         - 删除所有 `internal/model` 包的 import
         - 使用 service 包中的类型定义(Account, Platform常量等)
      
      2. **修复类型转换**
         - JSONB → map[string]any
         - 添加 mergeJSONB 辅助函数
         - 添加 Account.IsGemini() 方法
      
      3. **更新中间件调用**
         - GetUserFromContext → GetAuthSubjectFromContext
         - 适配新的并发控制签名(传递 ID 和 Concurrency 而不是完整对象)
      
      4. **修复 handler 层**
         - 更新 gemini_v1beta_handler.go
         - 修正 billing 检查和 usage 记录
      
      ## 影响范围
      - backend/internal/service/gemini_*.go
      - backend/internal/service/account_test_service.go
      - backend/internal/service/crs_sync_service.go
      - backend/internal/handler/gemini_v1beta_handler.go
      - backend/internal/handler/gateway_handler.go
      - backend/internal/handler/admin/account_handler.go
      9db52838
    • ianshaw's avatar
      fix(sse): 修复非标准 SSE 格式解析问题 · 16eec4eb
      ianshaw authored
      部分上游 API 返回的 SSE 格式不符合标准规范:
      - 标准格式: `data: {...}`(冒号后有空格)
      - 非标准格式: `data:{...}`(冒号后无空格)
      
      使用预编译正则 `^data:\s*` 统一处理两种格式。
      16eec4eb
    • Forest's avatar
      refactor: 封装 Redis key 生成函数 · 06d5876b
      Forest authored
      06d5876b
    • Forest's avatar
      refactor: 调整项目结构为单向依赖 · e5a77853
      Forest authored
      e5a77853
    • ianshaw's avatar
    • ianshaw's avatar
      feat(service): 改进 Gemini OAuth 服务层,区分 Code Assist 和 AI Studio 客户端 · 456e8984
      ianshaw authored
      OAuth 服务改进:
      - 添加 GetOAuthConfig 返回 AI Studio OAuth 可用性
      - Code Assist 强制使用内置 Gemini CLI 客户端
      - AI Studio OAuth 要求用户配置自定义 OAuth 客户端
      - ExchangeCode/RefreshToken 接口添加 oauthType 参数
      - 添加 unauthorized_client 错误的向后兼容重试逻辑
      
      兼容层改进:
      - 403 重试逻辑仅对 Code Assist OAuth 生效
      - 添加 insufficient-scope 错误检测,避免无效重试
      - 上游错误消息脱敏处理(隐藏 API key 等敏感信息)
      - 改进错误提示,显示更多上游错误详情
      456e8984
    • ianshaw's avatar
      fix(backend): 移除对已删除 ports 包的依赖 · 85fd1e4a
      ianshaw authored
      适配 main 分支的 ports 目录删除重构:
      - 将 ports 包中的接口移至 service 包
      - 更新 repository 层的导入路径
      85fd1e4a
    • ianshaw's avatar
      fix(backend): 修复 golangci-lint 报告的格式和代码规范问题 · 6682d06c
      ianshaw authored
      - gofmt: 修复 account_handler.go, models.go, gemini_messages_compat_service.go 的格式
      - staticcheck ST1005: 将 error strings 改为小写开头
      6682d06c
    • ianshaw's avatar
      fix(backend): 修复 golangci-lint 报告的问题 · efa470ef
      ianshaw authored
      - gofmt: 修复代码格式问题
      - errcheck: 处理 WriteString 和 Close 返回值
      - staticcheck: 错误信息改为小写开头
      - staticcheck: 移除无效的 nil 检查
      - staticcheck: 使用 append 替换循环
      - staticcheck: 使用无条件的 TrimPrefix
      - ineffassign: 移除无效赋值
      - unused: 移除未使用的 geminiOAuthService 字段
      - 重新生成 wire_gen.go
      efa470ef
    • ianshaw's avatar
      feat(backend): 实现 Gemini AI Studio OAuth 和消息兼容服务 · b2d71da2
      ianshaw authored
      - gemini_oauth_service.go: 新增 AI Studio OAuth 类型支持
      - gemini_token_provider.go: Token 提供器增强
      - gemini_messages_compat_service.go: 支持 AI Studio 端点
      - account_test_service.go: Gemini 账户可用性检测
      - gateway_service.go: 网关服务适配
      - openai_gateway_service.go: OpenAI 兼容层调整
      b2d71da2
    • ianshaw's avatar
      feat(backend): 完善 Gemini OAuth Token 处理 · 03a8ae62
      ianshaw authored
      - 修复 account_handler 中 token 字段类型转换(int64 转 string)
      - 增强 Account.GetCredential 支持多种数值类型(float64, int, json.Number 等)
      - 添加 Account.IsGemini() 方法用于平台判断
      - 优化 refresh_token 和 scope 的空值处理
      03a8ae62
    • ianshaw's avatar
      feat(handler): 添加 Gemini OAuth Handler 和完善依赖注入 · e36fb98f
      ianshaw authored
      - 新增 Gemini OAuth 授权处理器
      - 扩展账号和网关处理器支持 Gemini
      - 注册 Gemini 相关路由
      - 更新 Wire 依赖注入配置(所有层)
      - 更新 Docker Compose 配置
      e36fb98f
    • ianshaw's avatar
      feat(service): 扩展 CRS 同步和定价服务支持 Gemini · 55258bf0
      ianshaw authored
      - CRS 同步服务新增 Gemini 账号同步逻辑(+273行)
      - 定价服务扩展 Gemini 模型定价计算(+99行)
      - 更新 Token 刷新服务集成 Gemini
      - 更新相关单元测试
      55258bf0
    • ianshaw's avatar
      feat(service): 实现 Gemini OAuth 和 Token 管理服务 · dc109827
      ianshaw authored
      - 实现 OAuth 授权流程服务
      - 添加 Token 提供者和自动刷新机制
      - 实现 Gemini Messages API 兼容层
      - 更新服务容器注册
      dc109827
    • ianshaw's avatar
      feat(service): 定义 Gemini 服务端口接口 · 71c28e43
      ianshaw authored
      - 定义 OAuth 服务接口
      - 定义 Token 缓存服务接口
      - 定义 Code Assist 服务接口
      71c28e43
    • shaw's avatar
      chore: 调整403重试次数跟间隔 · b3463769
      shaw authored
      b3463769
    • Forest's avatar
      refactor: 调整 server 目录结构 · 57fd1722
      Forest authored
      57fd1722
  3. 25 Dec, 2025 10 commits
    • shaw's avatar
      b31698b9
    • Forest's avatar
      refactor: 自定义业务错误 · eeaff85e
      Forest authored
      eeaff85e
    • Forest's avatar
      refactor: 删除 ports 目录 · f51ad2e1
      Forest authored
      f51ad2e1
    • hi_yueban's avatar
      fix: 修复 OpenAI 账号 5h/7d 使用限制显示错误的问题 (#30) · f57f12c6
      hi_yueban authored
      * fix: 修复 OpenAI 账号 5h/7d 使用限制显示错误的问题
      
      问题描述:
      - 账号管理页面中,OpenAI OAuth 账号的 5h 列显示 7 天的剩余时间
      - 7d 列却显示几小时的剩余时间
      - 根本原因: OpenAI 响应头中 primary/secondary 的实际含义与代码假设相反
      
      修复方案:
      1. 后端归一化 (openai_gateway_service.go):
         - 根据 window_minutes 动态判断哪个是 5h/7d 限制
         - 新增规范字段 codex_5h_* 和 codex_7d_*
         - 保留旧字段以兼容性
      
      2. 前端适配 (AccountUsageCell.vue):
         - 优先使用新的规范字段
         - Fallback 到旧字段时基于 window_minutes 动态判断
         - 更新 computed 属性命名
      
      3. 类型定义更新 (types/index.ts):
         - 添加新的规范字段定义
         - 更新注释说明实际语义由 window_minutes 决定
      
      🤖
      
       Generated with Claude Code and Codex collaboration
      Co-Authored-By: default avatarClaude Sonnet 4.5 <noreply@anthropic.com>
      Co-Authored-By: default avatarOpenAI Codex <noreply@openai.com>
      
      * fix: 改进窗口判断逻辑,修复两个窗口都小于阈值时的bug
      
      问题:
      当两个窗口都小于360分钟时(如 primary=180分钟,secondary=300分钟),
      之前的逻辑会导致:
      - primary5h = true, secondary5h = true
      - 5h 字段会使用 primary(错误)
      - 7d 字段没有数据(bug)
      
      修复方案:
      改用比较策略:
      1. 当两个窗口都存在时:较小的分配给5h,较大的分配给7d
      2. 当只有一个窗口时:根据大小(<=360分钟)判断是5h还是7d
      3. 确保数据不会丢失,逻辑更健壮
      
      示例:
      - Primary: 180分钟, Secondary: 300分钟
        → 5h 使用 Primary(180分钟), 7d 使用 Secondary(300分钟) ✓
      
      🤖
      
       Generated with Claude Code
      Co-Authored-By: default avatarClaude Sonnet 4.5 <noreply@anthropic.com>
      
      * fix: 修正窗口大小判断逻辑 - 不能用剩余时间判断窗口类型
      
      **严重bug修复:**
      之前的 fallback 逻辑错误地使用 reset_after_seconds 来判断窗口大小。
      
      问题示例:
      - 周限制(7d)剩余 2h → reset_after_seconds = 7200秒
      - 5h限制 剩余 4h → reset_after_seconds = 14400秒
      - 错误逻辑:7200/60 < 14400/60,把周限制当成5h 
      
      根本问题:
      - window_minutes = 窗口的总大小(300 or 10080)
      - reset_after_seconds = 距离重置的剩余时间(变化的)
      - 不能用剩余时间来判断窗口类型!
      
      修复方案:
      1. **只使用 window_minutes** 来判断窗口大小
      2. 移除错误的 reset_after_seconds fallback
      3. 如果 window_minutes 都不存在,使用传统假设
      4. 添加详细注释说明这个陷阱
      
      🤖
      
       Generated with Claude Code
      Co-Authored-By: default avatarClaude Sonnet 4.5 <noreply@anthropic.com>
      
      * fix: 修复 lint 问题 - 改进 fallback 逻辑的变量赋值
      
      问题:
      第882-883行的简单布尔赋值可能触发 ineffassign 或 staticcheck 警告:
        use5hFromSecondary = snapshot.SecondaryUsedPercent != nil
        use7dFromPrimary = snapshot.PrimaryUsedPercent != nil
      
      修复:
      改用明确的 if 语句检查任意字段是否存在,更符合代码意图:
      - 如果 secondary 的任意字段存在,将其视为 5h
      - 如果 primary 的任意字段存在,将其视为 7d
      
      这样逻辑更清晰,也避免了 lint 警告。
      
      ---------
      Co-authored-by: default avatarClaude Sonnet 4.5 <noreply@anthropic.com>
      Co-authored-by: default avatarOpenAI Codex <noreply@openai.com>
      f57f12c6
    • shaw's avatar
      chore: 调整403重试次数跟间隔 · 8fbe1ad7
      shaw authored
      8fbe1ad7
    • 刀刀's avatar
      CC 400 返回具体错误信息 && 非 CC 请求时增加 system prompt (#26) · 9d30ceae
      刀刀 authored
      * feat: http 400 返回具体错误
      
      * 更新 workflows
      
      * 优化打包/docker 构建流程
      
      * 400 是返回 原始错误 - json 格式
      
      * feat: 非 cc请求时补充 system
      
      * go mod tidy
      9d30ceae
    • IanShaw's avatar
      feat: CRS 同步增强 - 自动刷新 OAuth token 和修复测试配置 (#27) · 60f6ed6b
      IanShaw authored
      * fix(service): 修复 OpenAI Responses API 测试负载配置
      
      - 所有账号类型统一添加 instructions 字段(不再仅限 OAuth)
      - Responses API 要求所有请求必须包含 instructions 参数
      
      * feat(crs-sync): CRS 同步时自动刷新 OAuth token 并保留完整 extra 字段
      
      **核心功能**:
      - CRSSyncService 注入 OAuth 服务依赖(Anthropic + OpenAI)
      - 账号创建/更新后自动刷新 OAuth token,确保可用性
      - 完整保留 CRS extra 字段,避免数据丢失
      
      **Extra 字段增强**:
      - 保留 CRS 所有原始 extra 字段
      - 新增同步元数据: crs_account_id, crs_kind, crs_synced_at
      - Claude 账号: 从 credentials 提取 org_uuid/account_uuid 到 extra
      - OpenAI 账号: 映射 crs_email -> email
      
      **Token 刷新逻辑**:
      - 新增 refreshOAuthToken() 方法处理 Anthropic/OpenAI 平台
      - 保留原有 credentials 字段,仅更新 token 相关字段
      - 刷新失败静默处理,不中断同步流程
      
      **依赖注入**:
      - wire_gen.go: CRSSyncService 新增 oAuthService/openaiOAuthService
      
      * style(crs-sync): 使用 switch 替代 if-else 修复 golangci-lint 警告
      
      - 将 refreshOAuthToken 中的 if-else 改为 switch 语句
      - 符合 staticcheck 规范
      - 添加 default 分支处理未知平台
      60f6ed6b
    • ianshaw's avatar
      fix(backend): handle defer Close() errors in crs_sync_service · 372a0129
      ianshaw authored
      修复 golangci-lint 错误检查问题
      - 使用匿名函数包装 defer Close() 并忽略错误
      - 符合 Go 最佳实践
      372a0129
    • ianshaw's avatar
      feat(account): 优化批量更新实现,使用统一 SQL 合并 JSONB 字段 · 62ed5422
      ianshaw authored
      - 新增 BulkUpdate 仓储方法,使用单条 SQL 更新所有账户
      - credentials/extra 使用 COALESCE(...) || ? 合并,只更新传入的 key
      - name/proxy_id/concurrency/priority/status 只在提供时更新
      - 分组绑定仍逐账号处理(需要独立操作)
      - 前端优化:Base URL 留空则不修改,按勾选字段更新
      - 完善 i18n 文案:说明留空不修改、批量更新行为
      62ed5422
    • ianshaw's avatar
      feat(account): 添加批量编辑账户凭据功能并优化 CRS 同步 · 2e76302a
      ianshaw authored
      - 新增批量更新账户凭据接口(account_uuid/org_uuid/intercept_warmup_requests)
      - 新增前端批量编辑模态框组件
      - 优化 CRS 同步逻辑,改进 extra 字段处理
      - 优化 CRS 同步 UI,添加更详细的结果展示
      - 完善国际化文案(中英文)
      2e76302a
  4. 24 Dec, 2025 5 commits
    • ianshaw's avatar
      feat(account): 添加从 CRS 同步账户功能 · 65538280
      ianshaw authored
      - 添加账户同步 API 接口 (account_handler.go)
      - 实现 CRS 同步服务 (crs_sync_service.go)
      - 添加前端同步对话框组件 (SyncFromCrsModal.vue)
      - 更新账户管理界面支持同步操作
      - 添加账户仓库批量创建方法
      - 添加中英文国际化翻译
      - 更新依赖注入配置
      65538280
    • shaw's avatar
      feat(settings): 添加文档链接配置功能 · 2e7818d6
      shaw authored
      - 后台系统设置新增文档链接(doc_url)配置项
      - 首页顶部导航栏显示文档链接图标(条件渲染)
      - Footer区域添加文档链接和GitHub链接
      - 支持中英文国际化
      2e7818d6
    • Forest's avatar
      refactor: 重命名 go module · 836c4dda
      Forest authored
      836c4dda
    • shaw's avatar
      fix(concurrency): 重构并发管理使用独立Key+原生TTL · e65e9587
      shaw authored
      问题:旧方案使用计数器模式,每次acquire都刷新TTL,导致僵尸数据永不过期
      
      解决方案:
      - 每个槽位使用独立Redis Key: concurrency:account:{id}:{requestID}
      - 利用Redis原生TTL,每个槽位独立5分钟过期
      - 服务崩溃后僵尸数据自动清理,无需手动干预
      - 兼容多实例K8s部署
      
      技术改动:
      - 新增SCAN脚本统计活跃槽位数量
      - 移除冗余的releaseScript,直接使用DEL命令
      - Wait队列TTL只在首次创建时设置,避免刷新
      e65e9587
    • shaw's avatar
      feat(gateway): 添加上游错误重试机制 · ad54795a
      shaw authored
      - OAuth/Setup Token 账号遇到 403 错误时,等待 2 秒后重试,最多 3 次
      - Console 账号遇到未配置的错误码时,同样进行重试
      - 重试耗尽后:OAuth 403 标记账号异常,Console 未配置错误码不标记账号
      - 移除 handleErrorResponse 中已被重试逻辑覆盖的死代码
      ad54795a