QTom
b2141a96e2
fix(ci): 修复 golangci-lint 和 API 合约测试失败
...
- 修复 errcheck: singleflight 返回值类型断言添加 ok 检查
- 修复 gofmt: 格式化 setting_service.go 和 claude_code_validator_test.go
- 修复 TestAPIContracts: 在 GET /admin/settings 期望中添加 min_claude_code_version 字段
2026-03-01 16:39:21 +08:00
QTom
4280aca82c
feat(gateway): 添加 Claude Code 客户端最低版本检查功能
...
- 通过 User-Agent 识别 Claude Code 客户端并提取版本号
- 在网关层验证客户端版本是否满足管理员配置的最低要求
- 在管理后台提供版本要求配置选项(英文/中文双语)
- 实现原子缓存 + singleflight 防止并发问题和 thundering herd
- 使用 context.WithoutCancel 隔离 DB 查询,避免客户端断连影响缓存
- 双 TTL 策略:60s 正常、5s 错误恢复,保证性能与可用性
- 仅检查 Claude Code 客户端,其他客户端不受影响
- 添加完整单元测试覆盖版本提取、比对、上下文操作
2026-03-01 15:45:44 +08:00
shaw
fbfbb26fd2
fix(ci): 将 gosec 集成到 golangci-lint 解决安全扫描超时
...
standalone gosec 扫描 24 万行 Go 代码在 CI 中持续超时,
将其作为 golangci-lint 的内置 linter 运行,复用 AST 解析和缓存大幅提速。
- 在 .golangci.yml 中启用 gosec 并迁移原有排除规则
- golangci-lint timeout 从 5m 提升到 30m
- 从 security-scan.yml 移除 standalone gosec 步骤
- 删除不再需要的 .gosec.json 配置文件
2026-02-28 23:12:38 +08:00
Wesley Liddick
493bd188d5
Merge pull request #680 from alfadb/fix/ops-normalize-nil-error-type
...
fix(ops): validate error_type against known whitelist before classification
2026-02-28 22:39:32 +08:00
Wesley Liddick
9fd95df5cf
Merge pull request #679 from DaydreamCoding/feat/account-rpm-limit
...
feat: 添加账号级别 RPM(每分钟请求数)限流功能
2026-02-28 22:37:10 +08:00
Wesley Liddick
4587c3e53e
Merge pull request #670 from DaydreamCoding/feat/admin-apikey-group-update
...
feat(admin): 添加管理员直接修改用户 API Key 分组的功能
2026-02-28 22:20:29 +08:00
shaw
be18bc6fc3
chore: 恢复数据库迁移文件060和修正版本号
2026-02-28 22:02:01 +08:00
QTom
212cbbd3a2
fix: add missing rpmCache nil arg in sora_client_handler_test
2026-02-28 21:30:59 +08:00
QTom
6f9e690345
test(sora): 补充测试 stub 中缺失的 AddGroupToAllowedGroups 方法
...
feat/admin-apikey-group-update 分支给 UserRepository 接口新增了
AddGroupToAllowedGroups 方法,需要在测试 stub 中补充实现以通过编译。
- sora_client_handler_test.go: stubUserRepoForHandler
- sora_generation_service_test.go: stubUserRepoForQuota
2026-02-28 20:55:31 +08:00
QTom
115d06edf0
fix: 修复 gofmt 格式问题
2026-02-28 20:38:35 +08:00
QTom
e135435ce2
fix: sync test constructor calls with new rpmCache parameter
...
Add missing nil argument for rpmCache to NewAccountHandler (5 sites)
and NewGatewayService (2 sites) after RPM feature expanded their
signatures.
2026-02-28 20:38:35 +08:00
QTom
cd09adc3cc
fix: add sanitizeExtraBaseRPM to BatchCreate handler
...
Ensures base_rpm validation (clamp 0-10000) is consistent across
all four account mutation paths: Create, Update, BulkUpdate, BatchCreate.
2026-02-28 20:38:06 +08:00
QTom
2491e9b5ad
fix: round-3 review fixes for RPM limiting
...
- Add sanitizeExtraBaseRPM to BulkUpdate handler (was missing)
- Add WindowCost scheduling checks to legacy non-sticky selection
paths (4 sites), matching existing sticky + load-aware coverage
- Export ParseExtraInt from service package, remove duplicate
parseExtraIntForValidation from admin handler
2026-02-28 20:38:06 +08:00
QTom
e63c83955a
fix: address deep code review issues for RPM limiting
...
- Move IncrementRPM after Forward success to prevent phantom RPM
consumption during account switch retries
- Add base_rpm input sanitization (clamp to 0-10000) in Create/Update
- Add WindowCost scheduling checks to legacy path sticky sessions
(4 check sites + 4 prefetch sites), fixing pre-existing gap
- Clean up rpm_strategy/rpm_sticky_buffer when disabling RPM in
BulkEditModal (JSONB merge cannot delete keys, use empty values)
- Add json.Number test cases to TestGetBaseRPM/TestGetRPMStickyBuffer
- Document TOCTOU race as accepted soft-limit design trade-off
2026-02-28 20:38:06 +08:00
QTom
ff9683b0fc
fix: move RPM prefetch before routing segment in legacy/mixed paths
...
Ensures isAccountSchedulableForRPM calls within the routing segment
hit the prefetch cache instead of querying Redis individually.
2026-02-28 20:37:37 +08:00
QTom
607237571f
fix: address code review issues for RPM limiting feature
...
- Use TxPipeline (MULTI/EXEC) instead of Pipeline for atomic INCR+EXPIRE
- Filter negative values in GetBaseRPM(), update test expectation
- Add RPM batch query (GetRPMBatch) to account List API
- Add warn logs for RPM increment failures in gateway handler
- Reset enableRpmLimit on BulkEditAccountModal close
- Use union type 'tiered' | 'sticky_exempt' for rpmStrategy refs
- Add design decision comments for rdb.Time() RTT trade-off
2026-02-28 20:37:37 +08:00
QTom
37fa980565
feat: flatten RPM config fields in Account DTO
2026-02-28 20:37:10 +08:00
QTom
f648b8e026
feat: increment RPM counter before request forwarding
2026-02-28 20:37:10 +08:00
QTom
678c3ae132
feat: integrate RPM scheduling checks into account selection flow
2026-02-28 20:37:10 +08:00
QTom
c1c31ed9b2
feat: wire RPMCache into GatewayService and AccountHandler
2026-02-28 20:35:38 +08:00
QTom
777be05348
feat: add RPMCache interface and Redis implementation with Lua scripts
2026-02-28 20:34:22 +08:00
QTom
0bb3e4a98c
feat: add RPM getter methods and schedulability check to Account model
2026-02-28 20:34:22 +08:00
QTom
9a91815b94
feat(admin): 完整实现管理员修改用户 API Key 分组的功能
...
## 核心功能
- 添加 AdminUpdateAPIKeyGroupID 服务方法,支持绑定/解绑/保持不变三态语义
- 实现 UserRepository.AddGroupToAllowedGroups 接口,自动同步专属分组权限
- 添加 HTTP PUT /api-keys/:id handler 端点,支持管理员直接修改 API Key 分组
## 事务一致性
- 使用 ent Tx 保证专属分组绑定时「添加权限」和「更新 Key」的原子性
- Repository 方法支持 clientFromContext,兼容事务内调用
- 事务失败时自动回滚,避免权限孤立
## 业务逻辑
- 订阅类型分组阻断,需通过订阅管理流程
- 非活跃分组拒绝绑定
- 负 ID 和非法 ID 验证
- 自动授权响应,告知管理员成功授权的分组
## 代码质量
- 16 个单元测试覆盖所有业务路径和边界用例
- 7 个 handler 集成测试覆盖 HTTP 层
- GroupRepo stub 返回克隆副本,防止测试间数据泄漏
- API 类型安全修复(PaginatedResponse<ApiKey>)
- 前端 ref 回调类型对齐 Vue 规范
## 国际化支持
- 中英文提示信息完整
- 自动授权成功/失败提示
2026-02-28 20:18:14 +08:00
QTom
000e621eb6
feat(admin): 添加管理员直接修改用户 API Key 分组的功能
...
- 新增 PUT /api/v1/admin/api-keys/:id 端点,允许管理员修改任意用户 API Key 的分组绑定
- 跳过用户级权限校验但保留分组有效性验证,修改后触发认证缓存失效
- Service 层支持三态语义:nil=不修改,0=解绑,>0=绑定,<0=拒绝
- 指针值拷贝保证安全隔离,负数 groupID 返回 400 INVALID_GROUP_ID
- 前端 UserApiKeysModal 新增可点击的分组选择下拉框,支持多 Key 并发更新
- 下拉支持视口翻转和滚动关闭,按钮有 disabled 和加载状态
- 覆盖:后端 20 个单元测试 (Service 11 + Handler 9) + 前端 16 个 E2E 测试
- golangci-lint 0 issues, make test-unit 全部通过
2026-02-28 20:18:14 +08:00
alfadb
093d7ba858
fix(ops): use normalized error type for all classification functions
...
- Compute normalizedType once and pass to classifyOpsPhase,
classifyOpsSeverity, classifyOpsIsBusinessLimited, classifyOpsIsRetryable
instead of raw parsed.ErrorType
- Add test case verifying known type takes precedence over conflicting code
Addresses Copilot review feedback on PR #680 .
2026-02-28 19:28:08 +08:00
alfadb
ce006a7a91
fix(ops): validate error_type against known whitelist before classification
...
Upstream proxies (account 4, 112) return `"<nil>"` as the error.type in
their JSON responses — a Go fmt.Sprintf("%v", nil) artifact. Since
`normalizeOpsErrorType` only checked for empty string, the literal
"<nil>" passed through and poisoned the entire classification chain:
error_phase was misclassified as "internal" (instead of "request"),
severity was inflated to P2, and the stored error_type was meaningless.
Add `isKnownOpsErrorType` whitelist so any unrecognised type falls
through to the code-based or default "api_error" classification.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-02-28 19:28:08 +08:00
yangjianbo
1d1fc019dc
fix(lint): resolve data management staticcheck warnings
2026-02-28 15:05:54 +08:00
yangjianbo
bb664d9bbf
feat(sync): full code sync from release
2026-02-28 15:01:20 +08:00
erio
d1b684b782
fix: add 2K image default pricing at 1.5x base price
...
Previously 2K images used the same base price as 1K ($0.134).
Now 2K uses 1.5x multiplier ($0.201), consistent with 4K using 2x ($0.268).
- Backend: add 2K size branch in getDefaultImagePrice
- Frontend: update 2K placeholder from 0.134 to 0.201
- Tests: update assertions for new 2K default price
2026-02-27 17:37:30 +08:00
Wesley Liddick
19ea392d5d
Merge pull request #663 from touwaeriol/fix/update-antigravity-useragent-version
...
fix: update antigravity user-agent version to 1.19.6
2026-02-27 15:28:45 +08:00
erio
afec747d9e
fix: update antigravity user-agent version to 1.19.6
...
Update the default user-agent version from 1.18.4 to 1.19.6
to match the latest official antigravity client.
2026-02-27 12:31:51 +08:00
erio
7388fcce41
fix: gofmt alignment in constants.go
2026-02-27 09:52:50 +08:00
erio
a6f9f9f968
feat: replace gemini-3-pro-image with gemini-3.1-flash-image
...
- Add migration 060 to update model_mapping for all antigravity accounts
- Remove gemini-3-pro-image and gemini-3-pro-image-preview mappings
- Add gemini-3.1-flash-image and gemini-3.1-flash-image-preview mappings
- Update frontend usage window to show GImage for new model
- Update isImageGenerationModel to support new model
2026-02-27 09:52:50 +08:00
alfadb
e6969acb50
fix: address review - fix log wording and add response body assertion in test
2026-02-26 23:49:30 +08:00
alfadb
9489531431
fix(gateway): return 404 instead of fake 200 for unsupported count_tokens endpoint
...
PR #635 returned HTTP 200 with {"input_tokens": 0} when upstream doesn't
support count_tokens (404). This caused Claude Code CLI to trust the zero
value, believing context uses 0 tokens, so auto-compression never triggers.
Fix: return 404 with proper error body so CLI falls back to its local
tokenizer for accurate estimation. Return nil (not error) to avoid
polluting ops error metrics with expected 404s.
Affected paths:
- Passthrough APIKey accounts: upstream 404 now passed through as 404
- Antigravity accounts: same fix (was also returning fake 200)
2026-02-26 23:34:53 +08:00
shaw
4ac57b4edf
fix: 临时移除fast-mode-2026-02-01避免429问题
2026-02-26 15:44:28 +08:00
Wesley Liddick
0dd6986e28
Merge pull request #639 from cagedbird043/pr/refactor-antigravity-model-source
...
refactor(admin): 消除测试连接 Gemini 模型硬编码,统一由 DefaultModels 提供
2026-02-26 14:57:13 +08:00
cagedbird043
2fd6ac319b
feat(antigravity): 添加 Claude Opus/Sonnet 4.6 后端模型定义
2026-02-26 14:27:51 +08:00
cagedbird043
ba69736f55
refactor(admin): 测试连接模型列表改为复用 antigravity.DefaultModels,消除硬编码重复
2026-02-26 13:34:10 +08:00
shaw
c75c6b6858
fix: 将 DriveClient 注入 GeminiOAuthService,消除单元测试中的真实 HTTP 调用
...
FetchGoogleOneTier 原先在方法内部直接创建 DriveClient 实例,
导致单元测试中对 googleapis.com 发起真实 HTTP 请求,在 CI 环境
产生 401 错误。
将 DriveClient 作为依赖注入到 GeminiOAuthService,遵循项目
端口与适配器架构规范:
- 新增 repository/gemini_drive_client.go 作为 Provider
- 注册到 repository Wire ProviderSet
- 测试中使用 mockDriveClient 替代真实调用
2026-02-26 10:53:04 +08:00
Wesley Liddick
de61745bb2
Merge pull request #635 from alfadb/fix/count-tokens-fallback-for-proxy
...
fix: count_tokens 端点不支持时降级返回空值
2026-02-26 10:07:30 +08:00
alfadb
03bcd94ae5
fix: count_tokens 端点不支持时降级返回空值 (404 only)
...
第三方 Anthropic 中转站通常不支持 /v1/messages/count_tokens 端点,
上游返回 404 时降级返回 {input_tokens: 0},客户端 fallback 到本地估算。
- 仅匹配 404 状态码,语义明确:端点不存在
- 其他错误 (400/429/500) 保留原始处理链和 ops 遥测
- 无需解析错误消息内容,不依赖字符串匹配
- 新增 table-driven 测试覆盖 fallback 和 non-fallback 路径
2026-02-26 09:28:45 +08:00
cagedbird043
ece911521e
fix(antigravity): 修正 Gemini 3.1 Pro High/Low 发布日期为 2026-02-19
2026-02-25 20:18:19 +08:00
cagedbird043
5d95e59742
fix(admin): 补全 antigravity 测试连接下拉框的 Gemini 模型列表
2026-02-25 18:51:47 +08:00
cagedbird043
01d084bbfd
feat(antigravity): 新增 Gemini 3.1 Pro High 和 Gemini 3.1 Pro Low 模型支持
2026-02-25 18:51:47 +08:00
shaw
15f3ffb165
chore: 调整模型定价文件仓库
2026-02-25 13:50:21 +08:00
huangenjun
935ea66681
fix: 修复 sora_sdk_client 类型断言未检查的 errcheck lint 错误
...
使用安全的 comma-ok 模式替代裸类型断言,避免 golangci-lint errcheck 报错。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-02-25 11:43:08 +08:00
huangenjun
65d4ca2563
fix: 修复流式响应中 URL 的 & 被转义为 \u0026 的问题
...
新增 jsonMarshalRaw 使用 SetEscapeHTML(false) 替代 json.Marshal,
避免 HTML 字符转义导致客户端无法直接使用返回的 URL。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-02-25 11:32:56 +08:00
huangenjun
3c619a8da5
refactor: 使用 go-sora2api SDK 替代自建 Sora 客户端
...
使用 go-sora2api v1.1.0 SDK 替代原有 ~2000 行自建 HTTP/PoW/TLS 指纹代码,
SDK 提供高并发性能优化(实例级 rand、PoW 缓冲区复用、context.Context 支持)。
- 新增 SoraSDKClient 适配器实现 SoraClient 接口
- 精简 sora_client.go 为仅保留接口和类型定义
- 更新 Wire 绑定使用 SoraSDKClient
- 删除 SoraDirectClient、sora_curl_cffi_sidecar、sora_request_guard 等旧代码
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-02-25 10:15:38 +08:00
shaw
ded9b6c14e
fix: upgrade utls to v1.8.2 to resolve GO-2026-4512 vulnerability
2026-02-25 08:57:43 +08:00