1. 16 Mar, 2026 8 commits
    • erio's avatar
      feat(dashboard): add per-user drill-down for group, model, and endpoint distributions · 4b41e898
      erio authored
      Click on a group name, model name, or endpoint name in the distribution
      tables to expand and show per-user usage breakdown (requests, tokens,
      actual cost, standard cost).
      
      Backend: new GET /admin/dashboard/user-breakdown API with group_id,
      model, endpoint, endpoint_type filters.
      Frontend: clickable rows with expand/collapse sub-table in all three
      distribution charts.
      4b41e898
    • kunish's avatar
      fix(antigravity): add stream keepalive to prevent connection drops · d7957343
      kunish authored
      Antigravity streaming handlers were missing the keepalive mechanism
      that exists in the standard gateway, causing proxy/CDN idle timeouts
      to break connections during long thinking phases (e.g. claude-opus-4-6).
      This resulted in truncated responses with missing tool calls.
      
      Add StreamKeepaliveInterval support to all three Antigravity streaming
      paths: Claude SSE, Gemini SSE, and upstream passthrough.
      d7957343
    • Ethan0x0000's avatar
      fix: always attach OpenAI 5h/7d window stats regardless of zero values · fa782e70
      Ethan0x0000 authored
      Removes hasMeaningfulWindowStats guard so the /usage endpoint consistently
      returns WindowStats for both time windows. The frontend now controls
      zero-value display filtering at the component level.
      fa782e70
    • Ethan0x0000's avatar
      fix: allow empty extra payload to clear account quota limits · afd72abc
      Ethan0x0000 authored
      UpdateAccount previously required len(input.Extra) > 0, causing explicit
      empty payloads (extra:{}) to be silently skipped. Change condition to
      input.Extra != nil so clearing quota keys actually persists.
      afd72abc
    • erio's avatar
      71f72e16
    • erio's avatar
      fix(billing): add window expiration check to Redis rate limit Lua script · 67c05062
      erio authored
      The updateRateLimitUsageScript Lua script previously performed
      unconditional HINCRBYFLOAT on all usage counters without checking
      whether the rate limit window had expired. This caused usage to
      accumulate across window boundaries in Redis while the DB correctly
      reset on expiration, leading to incorrect 429 rate limiting that
      could persist for up to 24 hours.
      
      The Lua script now checks each window timestamp before incrementing:
      - If the window has expired, usage is reset to the current cost and
        the window timestamp is updated (matching DB-side semantics)
      - If the window is still valid, usage is accumulated normally
      
      This also resolves the async race condition where stale HINCRBYFLOAT
      tasks from the worker queue could pollute a freshly rebuilt cache
      after invalidation, since the script now self-corrects expired windows.
      
      Closes #1049
      67c05062
    • QTom's avatar
      fix(gateway): WS 连接池条件式 MarkBroken 防止跨请求串流 · 3741617e
      QTom authored
      正常终端事件(response.completed 等)退出后连接归还复用,
      仅异常路径(读写错误、error 事件、客户端断连)MarkBroken 销毁。
      
      Generate 模式:
      - 引入 cleanExit 标记,仅在 isTerminalEvent break 时设置 true
      - defer 中根据 cleanExit 决定是否 MarkBroken
      - 所有异常路径已在各自分支中提前调用 MarkBroken
      
      Ingress 模式:
      - 引入 lastTurnClean 标记,sendAndRelay 正常完成时设为 true
      - releaseSessionLease 根据 lastTurnClean 决定是否 MarkBroken
      - 错误路径重置 lastTurnClean = false
      - 客户端断连后 drain 仍保守 MarkBroken(L2916)
      3741617e
    • QTom's avatar
      fix(gateway): 防止 OpenAI Codex 跨用户串流 · ab4e8b2c
      QTom authored
      根因:多个用户共享同一 OAuth 账号时,conversation_id/session_id 头
      未做用户隔离,导致上游 chatgpt.com 将不同用户的请求关联到同一会话。
      
      HTTP SSE 修复:
      - 新增 isolateOpenAISessionID(apiKeyID, raw),将 API Key ID 混入
        session 标识符(xxhash),确保不同 Key 的用户产生不同上游会话
      - buildUpstreamRequest: OAuth 分支先 Del 客户端透传的 session 头,
        再用隔离值覆盖
      - buildUpstreamRequestOpenAIPassthrough: 透传路径同样隔离
      - ForwardAsAnthropic: Anthropic Messages 兼容路径同步修复
      - buildOpenAIWSHeaders: WS 路径的 OAuth session 头同步隔离
      ab4e8b2c
  2. 15 Mar, 2026 26 commits
  3. 14 Mar, 2026 6 commits
    • Elysia's avatar
      fix(gateway): 防止流式 failover 拼接腐化导致客户端收到双 message_start · 0e237326
      Elysia authored
      
      
      当上游在 SSE 流中途返回 event:error 时,handleStreamingResponse 已将
      部分 SSE 事件写入客户端,但原先的 failover 逻辑仍会切换到下一个账号
      并写入完整流,导致客户端收到两个 message_start 进而产生 400 错误。
      
      修复方案:在每次 Forward 调用前记录 c.Writer.Size(),若 Forward 返回
      UpstreamFailoverError 后 writer 字节数增加,说明 SSE 内容已不可撤销地
      发送给客户端,此时直接调用 handleFailoverExhausted 发送 SSE error 事件
      终止流,而非继续 failover。
      
      Ping-only 场景不受影响:slot 等待期的 ping 字节在 Forward 前后相等,
      正常 failover 流程照常进行。
      Co-Authored-By: default avatarClaude Sonnet 4.6 <noreply@anthropic.com>
      0e237326
    • SsageParuders's avatar
      fix: Bedrock 账户配额限制不生效,配额计数器始终为 $0.00 · 37c044fb
      SsageParuders authored
      applyUsageBillingEffects() 中配额更新条件仅检查了 AccountTypeAPIKey,
      遗漏了 AccountTypeBedrock,导致 Bedrock 账户的配额计数器永远不递增。
      扩展条件以同时支持 APIKey 和 Bedrock 类型。
      
      同时在前端账户筛选下拉框中添加 AWS Bedrock 选项。
      37c044fb
    • shaw's avatar
      fix: remove unused saveRecords method to pass lint · 39f8bd91
      shaw authored
      39f8bd91
    • erio's avatar
      fix(ops): tune aggregation constants to prevent PG overload · f59b66b7
      erio authored
      Increase MAX(bucket_start) query timeout from 3s to 5s to reduce
      timeout-induced fallbacks. Shrink backfill window from 30 days to
      1 hour so that fallback recomputation stays lightweight instead of
      scanning the entire retention range.
      f59b66b7
    • Rose Ding's avatar
      fix: 按 review 意见重构数据库备份服务(安全性 + 架构 + 健壮性) · 1047f973
      Rose Ding authored
      
      
      1. S3 凭证加密存储:使用 SecretEncryptor (AES-256-GCM) 加密 SecretAccessKey,
         防止备份文件中泄露 S3 凭证,兼容旧的未加密数据
      2. 修复 saveRecord 竞态条件:添加 recordsMu 互斥锁保护 records 的 load/save
      3. 恢复操作增加服务端验证:handler 层要求重新输入管理员密码,通过 bcrypt
         校验,前端弹出密码输入框
      4. pg_dump/psql/S3 操作抽象为接口:定义 DBDumper 和 BackupObjectStore 接口,
         实现放入 repository 层,遵循项目依赖注入架构规范
      5. 改为流式处理避免大数据库 OOM:备份时 pg_dump stdout -> gzip -> io.Pipe ->
         S3 upload;恢复时 S3 download -> gzip reader -> psql stdin,不再全量加载
      6. loadRecords 区分"无数据"和"数据损坏"场景:JSON 解析失败返回明确错误
      7. 添加 18 个核心逻辑单元测试:覆盖加密、并发、流式备份/恢复、错误处理等
      Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
      1047f973
    • wucm667's avatar