1636 Commits

Author SHA1 Message Date
win
73bbbb415c feat: 实例级隔离 — salt + 指纹版本可配置
Some checks failed
CI / test (push) Failing after 3s
CI / golangci-lint (push) Failing after 2s
Security Scan / backend-security (push) Failing after 2s
Security Scan / frontend-security (push) Failing after 2s
- 新增 gateway.instance_salt: 不同 sub2api 实例对相同输入产生不同 hash
  影响 user_id 重写和 session hash,防止跨实例指纹关联
- 新增 gateway.fingerprint_defaults: CLI 版本号/SDK 版本/OS/Arch 可配置
  每个实例可设不同值,与其他 sub2api 部署区分
- constants.go + identity_service.go 支持启动时覆盖默认指纹
- wire_gen.go 启动时读取配置并应用覆盖
2026-03-22 03:01:55 +08:00
win
43506e4f78 fix: 更新 Claude CLI 指纹版本 2.1.22→2.1.81, SDK 0.70.0→0.80.0
Some checks failed
CI / test (push) Failing after 4s
CI / golangci-lint (push) Failing after 3s
Security Scan / backend-security (push) Failing after 3s
Security Scan / frontend-security (push) Failing after 3s
2026-03-22 02:42:57 +08:00
win
3673936cb3 fix: Node.js TLS 代理仅拦截 Anthropic 请求(DoWithTLS 路径)
Some checks failed
CI / test (push) Failing after 4s
CI / golangci-lint (push) Failing after 4s
Security Scan / backend-security (push) Failing after 4s
Security Scan / frontend-security (push) Failing after 5s
- Do() 去掉 Node.js 代理拦截,Antigravity/Google 请求走原路径
- 只有 DoWithTLS 且 enableTLSFingerprint=true 时走 Node.js 代理
- 按平台分治:Anthropic → Node.js 原生 TLS,Google → 原有 uTLS/直连
2026-03-22 02:25:40 +08:00
win
764623c7a0 fix: Node.js TLS 代理对所有 HTTPS 上游生效,去掉域名白名单
Some checks failed
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
- 移除 proxy_hosts 白名单限制和 shouldRouteViaNodeProxy
- 所有 HTTPS 上游请求统一走 Node.js 代理
- 通过 X-Forwarded-Host 动态识别目标主机
- Anthropic / Gemini / 任意上游自动适配
- 移除诊断日志(已定位问题)
2026-03-22 01:42:44 +08:00
win
c179c348c6 diag: 在 DoWithTLS 路径也添加诊断日志
Some checks failed
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
2026-03-22 01:39:55 +08:00
win
fbcaab03da fix: Node.js TLS 代理按 proxy_hosts 白名单过滤 + 诊断日志
Some checks failed
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
- 新增 proxy_hosts 配置:可配置需要走 Node.js 代理的主机列表
- 默认仅代理 api.anthropic.com,Gemini/Sora 走原路径
- 添加 warn 级别诊断日志,输出请求的 scheme/host/hostname/should_route
- 用于定位 Anthropic 请求未命中 Node.js 代理的原因
2026-03-22 01:36:12 +08:00
win
c6a282c2e7 fix: Node.js TLS 代理按主机白名单过滤,Gemini 走原路径
Some checks failed
CI / test (push) Failing after 6m40s
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
CI / golangci-lint (push) Failing after 19m50s
- 新增 proxy_hosts 配置:白名单内的主机走 Node.js 代理
- 默认仅代理 api.anthropic.com
- Gemini/Sora 等非 Anthropic 请求自动走原有 uTLS 路径
- 解决 Gemini 请求经 Node.js 代理后 socket hang up 的问题
2026-03-22 01:15:56 +08:00
win
5c587c1095 fix: Node.js TLS 代理动态识别上游主机
Some checks failed
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
- Go: 通过 X-Forwarded-Host 传递原始目标主机给 Node.js 代理
- Node.js: 读取 X-Forwarded-Host 动态连接到正确的上游主机
- 所有 HTTPS 上游请求统一走代理,不再固定绑定 api.anthropic.com
- Gemini/Sora 等不同上游自动识别,无需手动配置
2026-03-22 01:09:39 +08:00
win
2fff535bcd fix: Node.js TLS 代理对所有 HTTPS 上游请求生效
Some checks failed
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
CI / test (push) Has been cancelled
Do() 方法新增 Node.js 代理检查,不再依赖账号级 TLS 指纹开关。
当 node_tls_proxy.enabled=true 时,所有 HTTPS 上游请求统一走
Node.js 代理,确保 JA3/JA4 指纹一致。
2026-03-22 01:01:38 +08:00
win
a72ba424cc feat: Node.js TLS 指纹代理 + 网络隔离防泄露
Some checks failed
CI / test (push) Failing after 1m32s
CI / golangci-lint (push) Failing after 33s
Security Scan / backend-security (push) Failing after 32s
Security Scan / frontend-security (push) Failing after 32s
- 新增 Node.js TLS Forward Proxy (tools/node-tls-proxy/)
  原生 Node.js TLS 栈发起上游 HTTPS,JA3/JA4 天然匹配 Claude CLI
  SSE 流式透传,支持上游 HTTP CONNECT 代理
  零依赖,Node.js 24.13.0 锁定版本

- Go 集成 (config.go + http_upstream.go)
  新增 NodeTLSProxyConfig 配置
  DoWithTLS 优先走 Node.js 代理模式,URL 重写 https→http://localhost:3456

- Docker 网络隔离 (docker-compose.tls-proxy.yml)
  sub2api 容器仅 internal 网络,物理隔离外网
  node-tls-proxy 唯一出站通道,IPv6 内核级禁用

- iptables 防泄露脚本 (tools/firewall/)
  QUIC/UDP 443 全局 DROP,仅 nodeproxy 用户可出站 TCP 443

- 镜像切换为 zfc931912343/ 仓库
2026-03-22 00:18:43 +08:00
mutuyihao
4feacf2213 fix(apicompat): support array content for system and tool messages 2026-03-21 15:34:28 +08:00
Wesley Liddick
186e36752d
Merge pull request #1194 from Ethan0x0000/feat/requested-upstream-model-semantics
feat(usage): 统一使用记录中的请求模型与上游模型语义
2026-03-21 14:02:10 +08:00
Wesley Liddick
421728a985
Merge pull request #1193 from xilu0/worktree-fix-thinking-block-log-level
fix: correct log levels for thinking block signature retry flow
2026-03-21 13:57:30 +08:00
Ethan0x0000
27948c777e fix(dto): fallback to legacy model in usage mapping
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-21 11:10:40 +08:00
Dave King
c64ed46d05 fix: correct log levels for thinking block signature retry flow
LegacyPrintf uses inferStdLogLevel() to infer log level from message
text. Any message containing the word "error" is classified as ERROR
level, causing the entire signature-retry recovery flow (which succeeds)
to produce spurious ERROR log entries.

Changes:
- Remove noisy [SignatureCheck] debug logs inside isThinkingBlockSignatureError
  that were logging every detected signature check as ERROR
- Change retry-start log to WARN level via [warn] prefix
- Change retry-success log to INFO level by removing "error" from message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 00:38:07 +00:00
Ethan0x0000
095200bd16 refactor(dto): split admin usage upstream model exposure
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-21 01:25:34 +08:00
Ethan0x0000
2c667a159c fix(provider): retain upstream model for gemini compat and ws
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-21 01:24:59 +08:00
Ethan0x0000
bac408044f fix(provider): preserve requested model in antigravity and sora
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-21 01:24:30 +08:00
Ethan0x0000
4edcfe1f7c fix(usage): preserve requested model in gateway billing paths
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-21 01:23:54 +08:00
Ethan0x0000
9259dcb6f5 test(repo): cover requested model repository semantics
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-21 01:23:20 +08:00
Ethan0x0000
7ef933c7cf feat(repo): persist requested model in usage log queries
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-21 01:22:49 +08:00
Ethan0x0000
7d312822c1 feat(usage): add requested model usage metadata helpers
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-21 01:22:16 +08:00
QTom
5c39e6f2fb fix(ops_alert): wg.Add 竞态修复 + leader lock release context 泄漏
1. Start() 中 wg.Add(1) 从 run() goroutine 内部移到 go s.run() 之前,
   防止 Stop().wg.Wait() 在 Add 之前返回导致孤儿 goroutine。
2. tryAcquireLeaderLock 返回的 release 闭包改用独立的
   context.Background()+5s 超时,避免捕获的 evaluateOnce ctx
   在 defer 执行时已过期导致锁释放失败(最长阻塞 90s TTL)。
2026-03-20 18:22:00 +08:00
Wesley Liddick
a225a241d7
Merge pull request #1162 from remxcode/main
feat(openai): 增加 gpt-5.4-mini/nano 模型支持与定价配置
2026-03-20 13:57:47 +08:00
Wesley Liddick
553a486d17
Merge pull request #1171 from wucm667/fix/quota-display-stale-after-reset
fix: quota display shows stale cumulative usage after daily/weekly reset
2026-03-20 13:54:18 +08:00
Wesley Liddick
c73374a221
Merge pull request #1176 from learnerLj/fix-bugs
fix: 修复 OpenAI 转发路径未应用分组默认模型映射
2026-03-20 13:53:20 +08:00
Jiahao Luo
4617ef2bb8 Fix OpenAI default model forwarding 2026-03-20 13:36:54 +08:00
alfadb
8afa8c1091 fix(apicompat): 修正 Anthropic→OpenAI 推理级别映射
旧映射错误地将所有级别上移一档(medium→high, high→xhigh),
导致 effort=max 被原样透传到 OpenAI 上游并返回 400 错误。

根据两边官方 API 定义对齐:
- Anthropic: low, medium, high(默认), max
- OpenAI:    low, medium, high(默认), xhigh

新的 1:1 映射:low→low, medium→medium, high→high, max→xhigh
2026-03-20 12:01:02 +08:00
Remx
578608d301 fix: format gpt-5.4 mini fallback pricing 2026-03-20 10:54:50 +08:00
wucm667
0d45d8669e fix: quota display shows stale cumulative usage after daily/weekly reset
The quota reset mechanism is lazy — quota_daily_used/quota_weekly_used
in the database are only reset on the next IncrementQuotaUsed call.
The scheduling layer (IsQuotaExceeded) correctly checks period expiry
before enforcing limits, so the account remains usable. However, the
API response mapper reads the raw DB value without checking expiry,
causing the frontend to display cumulative usage (e.g. 110%) even
after the reset period has passed.

Add IsDailyQuotaPeriodExpired/IsWeeklyQuotaPeriodExpired methods and
use them in the mapper to return used=0 when the period has expired.
2026-03-20 10:22:54 +08:00
shaw
4f7629a4cb fix: add max_claude_code_version to API contract test expected output 2026-03-20 09:17:32 +08:00
Wesley Liddick
9dccbe1b07
Merge pull request #1169 from touwaeriol/pr/credits-exhausted-fix
fix(antigravity): correctly mark credits exhausted on "Resource has been exhausted" 429
2026-03-20 09:12:55 +08:00
Wesley Liddick
9a88df7f28
Merge pull request #1167 from touwaeriol/pr/proxy-fast-fail
fix(antigravity): fast-fail on proxy unavailable, temp-unschedule account
2026-03-20 09:12:39 +08:00
Wesley Liddick
3529148455
Merge pull request #1151 from DaydreamCoding/feat/admin-user-group-filter
feat(admin): 用户管理新增分组列、分组筛选与专属分组一键替换
2026-03-20 09:10:38 +08:00
shaw
01d8286bd9 feat: add max_claude_code_version setting and disable auto-upgrade env var
Add maximum Claude Code version limit to complement the existing minimum
version check. Refactor the version cache from single-value to unified
bounds struct (min+max) with a single atomic.Value and singleflight group.

- Backend: new constant, struct field, cache refactor, validation (semver
  format + cross-validation max >= min), gateway enforcement, audit diff
- Frontend: settings UI input, TypeScript types, zh/en i18n
- Add CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 to all Claude Code
  tutorials on /keys page (unix/cmd/powershell/vscode settings.json)
2026-03-20 09:10:01 +08:00
erio
21b6f2d593 fix(antigravity): correctly mark credits exhausted on "Resource has been exhausted" 429
shouldMarkCreditsExhausted was blocked by isURLLevelRateLimit check when
credit overages retry returned "Resource has been exhausted (e.g. check quota).",
causing credits to never be marked as exhausted. This led to an infinite loop
where each request injected credits, bypassed model rate limits, and failed again.

- Remove isURLLevelRateLimit guard from shouldMarkCreditsExhausted (only called
  for credit retry responses — if credits retry fails, mark exhausted)
- Add "resource has been exhausted" to creditsExhaustedKeywords
- Update tests to match corrected behavior
2026-03-20 00:04:01 +08:00
erio
528ff5d28c fix(antigravity): fast-fail on proxy unavailable, temp-unschedule account
## Problem

When a proxy is unreachable, token refresh retries up to 4 times with
30s timeout each, causing requests to hang for ~2 minutes before
failing with a generic 502 error. The failed account is not marked,
so subsequent requests keep hitting it.

## Changes

### Proxy connection fast-fail
- Set TCP dial timeout to 5s and TLS handshake timeout to 5s on
  antigravity client, so proxy connectivity issues fail within 5s
  instead of 30s
- Reduce overall HTTP client timeout from 30s to 10s
- Export `IsConnectionError` for service-layer use
- Detect proxy connection errors in `RefreshToken` and return
  immediately with "proxy unavailable" error (no retries)

### Token refresh temp-unschedulable
- Add 8s context timeout for token refresh on request path
- Mark account as temp-unschedulable for 10min when refresh fails
  (both background `TokenRefreshService` and request-path
  `GetAccessToken`)
- Sync temp-unschedulable state to Redis cache for immediate
  scheduler effect
- Inject `TempUnschedCache` into `AntigravityTokenProvider`

### Account failover
- Return `UpstreamFailoverError` on `GetAccessToken` failure in
  `Forward`/`ForwardGemini` to trigger handler-level account switch
  instead of returning 502 directly

### Proxy probe alignment
- Apply same 5s dial/TLS timeout to shared `httpclient` pool
- Reduce proxy probe timeout from 30s to 10s
2026-03-19 23:48:37 +08:00
QTom
ba7d2aecbb feat(admin): 用户管理新增分组列、分组筛选与专属分组一键替换
- 新增分组列:展示用户的专属/公开分组,支持 hover 查看详情
- 新增分组筛选:下拉选择或模糊搜索分组名过滤用户
- 专属分组替换:点击专属分组弹出操作菜单,选择目标分组后
  自动授予新分组权限、迁移绑定的 Key、移除旧分组权限
- 后端新增 POST /admin/users/:id/replace-group 端点,事务内
  完成分组替换并失效认证缓存
2026-03-19 22:27:55 +08:00
Wesley Liddick
0236b97d49
Merge pull request #1134 from yasu-dev221/fix/openai-compat-prompt-cache-key
fix(openai): add fallback prompt_cache_key for compat codex OAuth requests
2026-03-19 22:02:08 +08:00
Wesley Liddick
26f6b1eeff
Merge pull request #1142 from StarryKira/fix/failover-exhausted-upstream-status-code
fix: record original upstream status code when failover exhausted (#1128)
2026-03-19 21:56:58 +08:00
Wesley Liddick
dc447ccebe
Merge pull request #1153 from hging/main
feat: add ungrouped filter to account
2026-03-19 21:55:28 +08:00
Wesley Liddick
550b979ac5
Merge pull request #1146 from DaydreamCoding/fix/test-403-error-status
fix(test): 测试连接收到 403 时将账号标记为 error 状态
2026-03-19 21:44:57 +08:00
Rose Ding
e443a6a1ea fix: 移除 staticcheck S1005 警告的多余 blank identifier
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 21:14:29 +08:00
Rose Ding
963494ec6f fix: Anthropic tool schema 转 Responses API 时补充缺失的 properties 字段
当 Claude Code 发来的 MCP tool 的 input_schema 为 {"type":"object"} 且缺少
properties 字段时,OpenAI Codex 后端会拒绝并报错:
Invalid schema for function '...': object schema missing properties.

新增 normalizeToolParameters 函数,在 convertAnthropicToolsToResponses 中
对每个 tool 的 InputSchema 做规范化处理后再赋给 Parameters。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 21:08:20 +08:00
Remx
42d73118fd feat(openai): 增加 gpt-5.4-mini/nano 模型支持与定价配置
- 接入 gpt-5.4-mini/nano 模型识别与规范化,补充默认模型列表
- 增加 gpt-5.4-mini/nano 输入/缓存命中/输出价格与计费兜底逻辑
- 同步前端模型白名单与 OpenCode 配置
- 补充 service tier(priority/flex) 计费回归测试
2026-03-19 19:03:13 +08:00
shaw
525cdb8830 feat: Anthropic 账号被动用量采样,页面默认展示被动数据
从上游 /v1/messages 响应头被动采集 5h/7d utilization 并存储到
Account.Extra,页面加载时直接读取本地数据而非调用外部 Usage API。
用户可点击"查询"按钮主动拉取最新数据,主动查询结果自动回写被动缓存。

后端:
- UpdateSessionWindow 合并采集 5h + 7d headers 为单次 DB 写入
- 新增 GetPassiveUsage 从 Extra 构建 UsageInfo (复用 estimateSetupTokenUsage)
- GetUsage 主动查询后 syncActiveToPassive 回写被动缓存
- passive_usage_ 前缀注册为 scheduler-neutral

前端:
- Anthropic 账号 mount/refresh 默认 source=passive
- 新增"被动采样"标签和"查询"按钮 (带 loading 动画)
2026-03-19 17:42:59 +08:00
shaw
a6764e82f2 修复 OAuth/SetupToken 转发请求体重排并增加调试开关 2026-03-19 16:56:18 +08:00
Hg
8027531d07 feat: add ungrouped filter to account 2026-03-19 15:42:21 +08:00
QTom
c1717c9a6c fix(test): 测试连接收到 403 时将账号标记为 error 状态
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:36:40 +08:00
haruka
1fd1a58a7a fix: record original upstream status code when failover exhausted (#1128)
When all failover accounts are exhausted, handleFailoverExhausted maps
the upstream status code (e.g. 403) to a client-facing code (e.g. 502)
but did not write the original code to the gin context. This caused ops
error logs to show the mapped code instead of the real upstream code.

Call SetOpsUpstreamError before mapUpstreamError in all failover-
exhausted paths so that ops_error_logger captures the true upstream
status code and message.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 11:15:02 +08:00