1306 Commits

Author SHA1 Message Date
zizi
63b9c880b5 Merge remote-tracking branch 'origin/main' into upgrade/upstream-v0.1.133-20260605
# Conflicts:
#	backend/internal/service/setting_service_public_test.go
2026-06-05 16:35:10 +08:00
DaydreamCoding
fe8952733a fix(usage): 管理端错误请求页过滤与分列完善
- 错误请求标签补传 model/account_id/group_id 过滤(此前 loadAdminErrors 丢弃),admin handler
  读取 model 查询参数走精确匹配
- 错误表格拆成 用户/API Key/账号 三独立列(上游行也显示用户),补 api_key_name/api_key_deleted,
  已删除 key 显示红色「已删除」标记;i18n keyDeletedBadge 补入 errorLog 命名空间

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:00:57 +08:00
DaydreamCoding
cf12bc521b fix(usage): 用量明细虚拟表对可空字段渲染崩溃致整表空白
- formatDuration 兜底 null(duration_ms 后端为 *int,count_tokens/失败等请求无耗时)
- tokens/cost 单元格与 CSV 导出加 (x ?? 0) 防御
- duration_ms 前端类型改 number|null,对齐后端指针,编译器从此拦未保护用法
- DataTable 虚拟化加固:initialRect 一屏兜底 + 过滤 0 高度读数

根因:渲染对 null 调 .toFixed() 抛错→Vue 弃整个 tbody→空白;虚拟化只渲可视行故呈概率性。
非 b3847fa 引入(formatDuration 自首个 commit 即存在)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 14:00:57 +08:00
DaydreamCoding
cfb195c7b2 feat(usage): 记录并展示失败请求(用户端+管理端)
- 记录失败请求并在用户端/管理端展示;分类下拉改用统一 Select 组件
- 模型过滤改后端 ILIKE 模糊匹配;新增「Key 名称」列(含已删除标记)与按 Key 过滤;时间列移至末列
- 用户可见「已删除 key 失败请求」:OpsErrorLogFilter 加 MatchDeletedKeyOwner,用户侧归属
  放宽为 (user_id OR deleted_key_owner_user_id),让 key 原所有者能看到删除 key 后继续请求
  导致的认证失败记录(他人仍 NotFound,不泄露存在性)
- 迁移 148:ops_error_logs 用户+时间索引

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:00:57 +08:00
DaydreamCoding
ddf063352a feat(ops): 错误日志 key 归因与早退字段补全
让 /admin/ops 错误详情正确归因 API key 并补全早退场景字段,合并三项改动:

- 鉴权早退补全用户/分组/平台字段:引入 ops fallback key(ContextKeyOpsFallbackAPIKey),
  apiKey 一加载成功即写入,覆盖分组停用/删除、Key 停用/过期/额度、用户停用、IP 限制等早退
  路径;ops 错误日志改用 getOpsAPIKey(正式 key 优先、回退键兜底),不改「已鉴权」语义。
- 已删除 key 归因(迁移 145):删除 key 时同一事务写 deleted_api_key_audits 映射,认证失败
  时用明文反查命中原所有者,错误详情展示「已删除 Key 所有者」「尝试的 Key 前缀」。
- 有效 key 报错快照前缀(迁移 147):对绑定有效 key 的错误,落库时快照明文前 8 位到
  api_key_prefix(与 attempted_key_prefix 互斥),key 之后被删仍保留报错当时真实前缀。

均仅对上线后新产生的错误/删除生效。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:00:57 +08:00
Wesley Liddick
a0057f44f2
Merge pull request #2932 from fatelei/issue-2917
fix: change balance to pointer type
2026-06-01 11:37:33 +08:00
Wesley Liddick
910ff3cd58
Merge pull request #2892 from Arron196/feat/sync-upstream-models-on-create
feat: 添加账号时支持同步上游支持的模型
2026-06-01 09:58:33 +08:00
Wesley Liddick
ed8f5666c6
Merge pull request #2895 from wucm667/feat/usage-window-tooltip
feat(admin): 账号用量窗口 5h/7d 增加说明 tooltip
2026-06-01 09:57:03 +08:00
fatelei
0560340bd4
fix: change balance to pointer type 2026-06-01 08:41:35 +08:00
DaydreamCoding
bf24b61139 perf(usage): 优化 /admin/usage 打开速度与刷新响应
根因:页面 mount 并发 6 个请求,其中 5 个在原始 usage_logs 上 live 聚合,
且有 1 个重复 getModelStats。优化(不引入预聚合):

前端
- UsageView 经 :model-options 下传 model 列表,移除 UsageFilters 重复的
  getModelStats(mount 请求 6→5,少一次 usage_logs 全表 GROUP BY model)
- 刷新/换筛选保留旧模型数据(invalidateModelStatsCache 只失效标记不清空数据),
  图表不再闪空,刷新期间页面保持可交互

后端
- GetStatsWithFilters 4 条聚合 errgroup 并行(仅 *sql.DB 连接池路径,ent.Tx
  顺序回退以保事务内不并发),endpoint 明细 best-effort;抑制取消级联噪声日志
- /admin/usage/stats 复用 dashboard 的 newSnapshotCache 30s 处理器层缓存,按
  filters+窗口为 key;前端手动刷新带 nocache=1 强制回源(刷新=最新)

注:自合并提交 4c8396c 迁移而来,仅取"列表打开速度与刷新响应"部分;原提交的
"审计查看弹窗大 body 渲染"改动(AuditLogModal / audit-log-format / 审计 i18n)
依赖尚未迁移的审计功能(d8389ade),本次已排除。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 18:56:08 +08:00
DaydreamCoding
b60d8bb4cc feat(usage): 在 /admin/usage 支持查看已删除用户的历史使用情况
用户软删除后使用记录仍在,但身份(邮箱)被 ent 软删除拦截器隐藏。本次在
三条管理员只读路径定点穿透软删除过滤,并把删除状态传播到前端标记,零新表/
迁移/回填:

- 后端穿透:富化 usage 日志(loadUsers)、用户搜索(ListWithFilters +
  UserListFilters.IncludeDeleted)、点击详情(GetByIDIncludeDeleted /
  GetUserIncludeDeleted + getById ?include_deleted 分支)
- 状态传播:service.User / dto.User 新增 DeletedAt;SearchUsers 标记 deleted
- 前端:表格与余额弹窗展示"已删除"徽标、筛选下拉标注并排序、点击走
  include_deleted;新增 i18n admin.usage.userDeletedBadge
- 安全:普通用户 usage 仅查本人(无 PII 泄漏);主用户列表与默认 getById
  行为不变(已删用户仍 404);仅 admin 搜索设 IncludeDeleted

后端 build / 三态 vet / unit 全量 / 仓储集成全绿;前端 typecheck / vitest /
改动文件 eslint 全清。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-30 17:52:18 +08:00
benjamin
57d9e15e04 feat: 添加账号时支持同步上游模型
新增 POST /admin/accounts/models/sync-upstream-preview 端点,
允许在创建账号流程中直接使用凭证同步上游支持的模型,
无需先保存账号获取 ID。

- 后端: 新增 SyncUpstreamModelsPreview handler
- 前端: 新增 syncUpstreamModelsPreview API 函数
- 前端: ModelWhitelistSelector 支持 syncCredentials prop
- 前端: CreateAccountModal 传递凭证给 ModelWhitelistSelector
2026-05-30 12:19:38 +08:00
wucm667
c256a5441a feat(admin): 账号用量窗口 5h/7d 增加说明 tooltip
在账号管理列表"用量窗口"列表头增加一个说明性 HelpTooltip,
解释 5h / 7d 是上游账号(如 OpenAI ChatGPT、Claude)官方的滚动
用量窗口限制,由上游设定、非 sub2api 配置、与映射模型无关,且
窗口滚动到期后自动重置、无法在 sub2api 端解除。

复用现有 HelpTooltip 组件(teleport 到 body,避免表格裁剪),
单个 ⓘ 图标置于列表头,避免每行重复。新增 i18n key
admin.accounts.usageWindowsHint(zh/en 同步)。纯展示说明,
不改用量计算与后端逻辑。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 20:57:29 +08:00
wucm667
c9caadb378 fix(account): address second-round review on quota auto-pause
- TopK initial filter now drops quota-paused accounts: fold the quota check
  into isAccountRequestCompatible so session-hash, TopK pool, and per-candidate
  rechecks all skip paused accounts. Previously the candidate pool was built
  without the quota check, so paused accounts could fill TopK and leave the
  scheduler returning "no available accounts" even with healthy ones available.
- Add per-account explicit disable flags auto_pause_5h_disabled /
  auto_pause_7d_disabled with toggles in EditAccountModal. Without these,
  leaving the account threshold blank silently falls back to the global default,
  so admins could not exempt a single account once a global default existed.
  Disable is per-window: an account can opt out of 5h auto-pause while still
  honoring 7d. Schedule snapshot whitelist includes the new fields, i18n EN/ZH
  updated, threshold-hint text revised to explain "blank = global default".
- Move quota auto-pause settings off the request hot path: replace the per-repo
  TTL+singleflight sync DB read with a per-SettingService stale-while-revalidate
  in-memory snapshot. Get is non-blocking (atomic.Pointer load + async refresh
  on staleness); writes via UpdateOpsAdvancedSettings push directly into the
  cache through an injected sink; wire warms the cache at startup. Adds Warm
  (sync) for tests/init and SetOpenAIQuotaAutoPauseSettings (sink target).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 14:32:45 +08:00
wucm667
8b7a822706 fix(account): address review on OpenAI quota auto-pause
- gate previous_response_id sticky path with quota auto-pause check at both
  the snapshot and DB-recheck stages (previously bypassed, #1)
- skip pausing when the usage window already reset to avoid a stale stuck-pause;
  carry codex_*_reset_at / reset_after_seconds / codex_usage_updated_at through
  the scheduler snapshot whitelist (#2)
- remove the incomplete limit mode; percentage threshold only (#3)
- add global default 5h/7d threshold inputs to the Ops settings dialog with
  validation and en/zh i18n (#4)
- downgrade account_auto_paused_by_quota log from Info to Debug; it fires
  per-candidate on the scheduling hot path (#5)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 12:20:30 +08:00
wucm667
ead471d64b feat(account): 支持按 5h/7d 用量阈值自动暂停账号调度 2026-05-29 10:47:47 +08:00
Wesley Liddick
433f8dcd13
Merge pull request #2834 from DaydreamCoding/pr/openai-codex-cli-allow-claude-code
feat(openai): codex_cli_only 新增放行 Claude Code Codex 插件的机制
2026-05-29 10:30:33 +08:00
shaw
514ac5c6a1 feat: 适配 claude-opus-4-8 2026-05-29 09:56:48 +08:00
shaw
37044b83eb fix(openai): clarify endpoint capability UI 2026-05-29 09:23:06 +08:00
shaw
ed1b57c597 fix(openai): gate routing by endpoint capability 2026-05-29 08:58:10 +08:00
lyen1688
1b2d8873b0 feat: 完善前置拦截审核运行态 2026-05-28 20:05:24 +08:00
DaydreamCoding
56908d3c4c feat(openai): codex_cli_only 新增放行 Claude Code Codex 插件的机制
适用场景:在 Claude Code 中使用 https://github.com/openai/codex-plugin-cc
插件时,插件经官方 codex app-server 以 clientInfo.name="Claude Code" 完成
initialize 握手,请求头被设为 originator=Claude Code、User-Agent 含
"Claude Code/",不在官方客户端白名单内,原本会被 codex_cli_only 拦截 403。

在官方客户端白名单未命中时评估两层独立放行(OR 语义):

- 按账号:account.Extra.codex_cli_only_allowed_clients 引用命名预设
  (目前仅 claude_code),detector reason=allowed_client_matched
- 全局开关:/admin/settings 网关服务 OpenAI 区块新增
  openai_allow_claude_code_codex_plugin(默认 false),开启后对所有
  codex_cli_only 账号统一放行,detector reason=global_allowed_client_matched

签名仍要求 originator=Claude Code 精确等值 + UA 含 "Claude Code/"。
上游转发保持透传不变。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 23:55:34 +08:00
Wesley Liddick
cc077862b3
Merge pull request #2797 from wucm667/feat/account-list-created-at-column
feat(admin): 账号管理列表新增创建时间列
2026-05-27 22:10:21 +08:00
Wesley Liddick
bbe847ed3e
Merge pull request #2805 from StarryKira/feat/configurable-pool-retry-status-codes
feat(account): configurable pool-mode same-account retry status codes
2026-05-27 22:09:55 +08:00
lyen1688
f597c1581b feat(group): 支持自定义 /v1/models 模型列表 2026-05-27 18:00:45 +08:00
shaw
a391635191 更新 OpenAI 使用密钥配置 2026-05-27 17:29:20 +08:00
zizi
7954492cee fix(ui): hide sidebar version badge 2026-05-27 14:28:29 +08:00
zizi
ac5ff854b2 feat(custom-menu): secure embedded shop pages
Add omit_auth_context as a safe default for custom menu iframe pages, converge untrusted public output, and document the deployed shop menu configuration.
2026-05-27 14:28:17 +08:00
StarryKira
21033dceb9 feat(account): configurable pool-mode same-account retry status codes
Pool mode currently retries the same account for a fixed set of
upstream HTTP statuses: 401, 403, 429. Some upstream pool deployments
also need same-account retry for transient provider/proxy statuses
such as 502, 503, 520, 529, but hard-coding more statuses changes
behavior for everyone.

Add a per-account credentials option `pool_mode_retry_status_codes`
that lets admins choose which upstream HTTP status codes trigger
same-account retry in pool mode:

- Unset (default): preserve the current 401/403/429 default
- Explicit list: override the defaults with the configured codes
- Codes normalized to the 100-599 range, deduplicated, sorted

The standalone `isPoolModeRetryableStatus` helper is kept as the
default-only fallback. All 15 gateway call sites switch to the new
`Account.IsPoolModeRetryableStatus` method so behavior is preserved
for accounts that do not configure the new field.

Frontend admin UI gains a "Retry Status Codes" comma-separated input
under the pool-mode section in both Create/Edit account modals
(en + zh i18n).

Fixes #2731

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 11:24:25 -07:00
wucm667
b6a38ddab7 feat(admin): 账号管理列表新增创建时间列 2026-05-26 19:59:12 +08:00
DaydreamCoding
11fe7de926 fix(account): 重新授权不再清空 Extra 配置
Claude / OpenAI 账号重新授权走通用 PUT /accounts/:id 时,后端
UpdateAccount 会全量覆盖 account.Extra(仅保留 5 个 quota 用量键),
导致 base_rpm / window_cost_limit / window_cost_sticky_reserve /
max_sessions / quota_* / privacy_mode 等持久化配置全部丢失。

新增专用接口 POST /accounts/:id/apply-oauth-credentials,沿用
现有 /refresh 路径模式:Credentials-only update + Extra JSONB
key 级合并(UpdateAccountExtra) + ClearError + InvalidateToken。

作用域:Claude OAuth / Claude Cookie auth / OpenAI OAuth 三个
调用点。Gemini / Antigravity 现有路径本就不传 extra,保持不变。

顺带修复:旧重新授权路径未调用 InvalidateToken,导致重新授权后
首请求可能仍用缓存中的旧 token 而立即 401。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 19:46:08 +08:00
Wesley Liddick
bebc082306
Merge pull request #2766 from DaydreamCoding/feat/user-platform-quota
feat(quota): 用户 × 平台 USD 配额
2026-05-26 14:13:18 +08:00
lyen1688
23f3d426c6 feat: 支持内容审计风险阈值配置 2026-05-26 13:58:02 +08:00
DaydreamCoding
6b39b344d8 feat(quota): 用户 × 平台 USD 配额
为用户在 anthropic/openai/gemini/antigravity 四个平台上提供日/周/月
三个窗口的 USD 配额管控。配额语义:未设置=不限制,0=禁用,>0=美元上限。

两层模型:
- 配置层:系统默认配额,以及 email/linuxdo/oidc/wechat/github/google/
  dingtalk 七个鉴权来源的默认配额,存于 settings,以嵌套 JSON 整体读写
  (系统 1 个 key + 每个来源 1 个 key),整体替换语义。
- 运行时层:user_platform_quota 表按用户记录实际配额,与配置层解耦。

后端:新增 ent schema 与 140_user_platform_quotas.sql 迁移、repository
与 service 端口、计费链路集成、管理端与用户端读写接口。
前端:管理端设置页配额编辑、用户配额管理 Modal、用户 Dashboard 展示、
中英文案。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 10:49:20 +08:00
shaw
0cfabaa82e fix(i18n): escape at-sign in email whitelist placeholder
Escape the at-sign in email whitelist placeholder to avoid Vue I18n linked message parsing errors on the settings page.
2026-05-23 14:18:20 +08:00
shaw
0430899748 feat(admin): add compact proxy IP resource link
Add a low-visibility proxy IP resource link near proxy-related controls.

- Show the link beside account proxy selectors

- Show the link in the create proxy dialog tab row

- Keep the entry inline to avoid interrupting form workflows
2026-05-23 14:18:19 +08:00
Wesley Liddick
f59d9a5f8e
Merge pull request #2674 from wucm667/feat/moderation-per-model-toggle
feat(risk-control): 内容审计支持按模型生效
2026-05-22 20:10:38 +08:00
Wesley Liddick
301032dc72
Merge pull request #2672 from wucm667/feat/email-whitelist-wildcard-suffix
feat(registration): 邮箱白名单支持后缀通配符匹配(*.edu.cn)
2026-05-22 17:33:29 +08:00
Wesley Liddick
a33a294970
Merge pull request #2658 from wucm667/feat/account-test-chat-completions-path
feat(account): 测试连接支持 OpenAI-compatible Chat Completions 路径
2026-05-22 17:31:14 +08:00
Wesley Liddick
e674a5628c
Merge pull request #2682 from Xch13/fix-cache-hit-rate
fix(frontend): 修正 Cache Hit Rate 计算分母,包含全部 prompt tokens
2026-05-22 17:27:26 +08:00
wucm667
ffd53343bb fix(deps): 升级 js-cookie 修复安全审计 2026-05-22 13:55:27 +08:00
Xch13
6ba20acd66 fix(frontend): correct Cache Hit Rate denominator to include all prompt tokens
Cache Hit Rate was calculated as cache_read / (cache_read + cache_creation),
which always yields 100% for OpenAI models since cache_creation is never
reported by the OpenAI API. The denominator should include all prompt tokens
(input_tokens + cache_read_tokens + cache_creation_tokens) so the rate
reflects the actual percentage of input tokens served from cache.

Fixes #2291
2026-05-22 11:45:33 +08:00
wucm667
0d5c6f7cc7 feat(risk-control): 内容审计支持按模型生效 2026-05-21 21:18:43 +08:00
wucm667
a5b9b68b76 feat(registration): 支持邮箱白名单后缀通配符 2026-05-21 21:02:26 +08:00
wucm667
ca60cede14 feat(account): 支持测试连接 Chat Completions 路径 2026-05-21 16:37:20 +08:00
shaw
a613a587ba feat: add subscription expiry email toggle 2026-05-21 14:27:50 +08:00
shaw
9673a22f26 fix(i18n):
去除兑换码批量修改重复的翻译 key

  PR #2613 与 PR #2615 各自独立添加了同一组批量修改 i18n key,
  导致 vue-tsc 报 TS1117 错误。保留 Title Case 一组,删除重复定义。
2026-05-21 11:12:32 +08:00
Wesley Liddick
eda04c6129
Merge pull request #2615 from wucm667/feat/redeem-code-batch-update
feat(redeem): 兑换码支持批量修改
2026-05-21 10:39:46 +08:00
Wesley Liddick
d3c4e50753
Merge pull request #2645 from lyen1688/fix/trusted-forwarded-ip-acl
PR:为 API Key IP 白/黑名单增加可配置的反代真实 IP 判断
2026-05-21 10:34:28 +08:00
lyen1688
08c8c67df7 为 API Key ACL 增加反代真实 IP 开关 2026-05-20 22:51:46 +08:00