yan9651688
60ff61132d
feat(accounts): make repeated static account setup safer
...
Admins often need another account with the same provider and routing configuration. Duplicate on the server so credentials never return to the browser, preserve exact group priorities atomically, start the copy paused, and recover the same copy after ambiguous idempotency-store failures.
Constraint: Admin account responses redact credentials, so duplication must remain server-side
Constraint: OAuth and setup-token credentials rotate and must not be shared across account rows
Rejected: Copy raw account JSON to the clipboard | exposes credentials outside the server
Rejected: Duplicate rotating credentials | account-scoped refresh locks can race token rotation
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep copies paused, avoid automatic upstream probes, and exclude rotating credential types unless token ownership is redesigned
Tested: Targeted Go tests, Go vet, server build; frontend lint, typecheck, Vitest suite, production build; integration test compiled
Not-tested: Docker-backed PostgreSQL execution because Docker is unavailable
Related: Wei-Shaw/sub2api#1379
Related: Wei-Shaw/sub2api#2928
2026-07-15 10:51:13 +08:00
Wesley Liddick
4355861ef2
Merge pull request #4269 from catoncat/agent/sub2api-agent-identity
...
feat(openai): support Codex Agent Identity authentication
2026-07-15 09:47:00 +08:00
Wesley Liddick
de52f7ba89
Merge pull request #4279 from bestony/agent/0268b42f/bes-21-groups-id-column
...
feat(admin): /admin/groups 列表设置新增 ID 列
2026-07-15 09:38:46 +08:00
cat
6485081122
feat(frontend): 标明 OpenAI 认证模式
2026-07-14 19:25:13 +08:00
bestony
eedd9b147d
feat(admin): add optional ID column on groups list
...
Add a toggleable group ID column in /admin/groups column settings.
It shows the group id (e.g. #1 ), is hidden by default for new and
existing admins via column-settings version migration, and remains
sortable against the existing backend sort_by=id support.
2026-07-14 19:19:22 +08:00
Heatherm Huang
343390057d
fix(grok): fail over OAuth credential errors safely
2026-07-14 14:55:30 +08:00
superman2003
d2d3fcf57b
feat(frontend): show Grok monitoring and Free plan badge
2026-07-14 12:24:42 +08:00
bestony and multica-agent
2c2e50ba58
feat(ops): add host filtering to system logs
...
Co-authored-by: multica-agent <github@multica.ai >
2026-07-14 01:29:46 +08:00
Wesley Liddick
0465540195
Merge pull request #4048 from iMouseWu/fix/datatable-scroll-jank
...
fix(frontend): 小数据量关闭 DataTable 虚拟化并按行主键缓存行高,消除账号列表滚动抖动
2026-07-13 15:32:08 +08:00
shaw
7cbb36f278
feat(billing): Codex alpha/search 网页搜索按次计费
...
- alpha/search 成功请求(上游 2xx)按次计费落 usage_logs(billing_mode=per_request),
上游错误透传/failover 不计费;使用 mandatory 池提交,池满同步兜底不丢扣费
- 单价默认 0.01 USD/次(官方 $10/1000 次),分组新增 web_search_price_per_call
覆盖价(0=免费,负数/留空=默认价),实际扣费叠加分组费率倍数(与 token 口径一致)
- 分组字段全链路:ent schema + 迁移 174 + 端口快照 v15 + admin 创建/更新 + DTO
- 前端分组表单(openai 平台)新增单次价格配置,实时预览应用当前倍率后的单次价格
- 该端点鉴权维持仅 OpenAI 分组(非 OpenAI 分组 404)
2026-07-13 09:54:51 +08:00
iMouseWu and Claude Opus 4.8
94a22b62f7
fix(frontend): 小数据量关闭 DataTable 虚拟化并按行主键缓存行高,消除账号列表滚动抖动
...
账号列表(可变行高)在 @tanstack/vue-virtual 始终开启虚拟化下,估算行高(72)
远小于真实行高(~157),滚动时每行首次测量触发滚动补偿,表现为"一跳一跳"。
- DataTable 新增 virtualizeThreshold(默认 100):行数不超过阈值时全量渲染,
彻底绕开虚拟器的估算/测量/补偿链路;超过才虚拟化,保留大列表性能
- DataTable 补 getItemKey(与模板 :key 一致的行主键):itemSizeCache 由 index 键
改为行主键,排序/筛选/跨阈值来回都复用正确的已测行高,连带修复 >阈值 档
排序即抖的既存问题
- 虚拟/全量两模式统一为 renderRows,共用同一套行与单元格;measure ref 仅虚拟模式绑定
- useSwipeSelect:全量渲染(虚拟窗口为空)时改用真实 DOM 行按坐标二分定位,
修复关闭虚拟化后滑动多选点错行的隐患;定位逻辑提取为可测的导出函数
- AccountsView:estimate-row-height 72→156 对齐真实行高;virtualize-threshold=50,
常用分页档全量渲染无抖动,pageSize=100 仍虚拟化以约束每行 AccountUsageCell 的首屏请求扇出
- 新增/强化测试:DataTable 虚拟化决策与 getItemKey、useSwipeSelect DOM 兜底定位
经三方评审会(Claude + Codex + 作者)两轮讨论达成共识后落地。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-11 17:13:19 +08:00
Lyonle
0464856c4a
feat(frontend): Fast/Flex 策略支持搜索选择用户
...
将手工 User ID 输入替换为带防抖的邮箱模糊搜索和多选标签,同时继续保存 user_ids。
回显已有用户邮箱并保留无法解析的历史 ID,补齐中英文文案路径及组件回归测试。
2026-07-10 22:27:15 +08:00
Lyonle
f2966530c5
feat(openai): 支持用户级 Fast/Flex 策略
2026-07-10 15:16:09 +08:00
shaw
1a3cc2a787
refactor: 重新设计用量页布局并新增延迟健康列
...
- /admin/usage 明细区收进单卡片:三个下划线 tab(用量明细/错误请求/用户排行) + 自适应筛选栏 + 内容
- 用户 Token 排行收编为第三个 tab:去掉独立邮箱搜索,懒挂载,点击行下钻回用量明细并回显用户
- 首Token/耗时合并为延迟列(首字/总耗时):阈值 10s/30s/60s 与 1min/3min/5min 四档配色,色条上下两段短渐变过渡(from-40% to-60%),管理端与用户端 /usage 共用
- 时长格式 ≥1min 简化为 Xm Ys、≥1h 为 Xh Ym
- UsageFilters/UsageTable/OpsErrorLogTable 增加 flat 嵌入模式(默认关闭不影响其他使用方)
2026-07-09 21:09:40 +08:00
Birditch and Claude Opus 4.8
b062b36646
feat(admin): 用量记录页新增"用户 Token 排行"面板
...
- 在 /admin/usage 新增按用户聚合的 Token 排行表(输入/输出/缓存/总 Token、请求数、费用)
- 支持按列排序、邮箱搜索、Top N (20/50/100/200),点击行下钻到该用户
- 复用现有筛选(用户/时间/模型/分组等)与既有 KPI 卡片、逐条日志
- 后端对 /admin/dashboard/user-breakdown 做加法扩展(向后兼容):
- UserBreakdownItem 增加 input_tokens/output_tokens/cache_tokens
- 新增 sort_by(白名单排序,防注入,缺省仍按 actual_cost)
- 新增 sort_by 转发单元测试;更新 UsageView.spec 稳定桩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-09 06:04:22 -04:00
shaw
d4952154ff
fix: bill Grok video per second and harden video usage logging
...
Follow-up fixes for the #3775 audit findings:
- Bill Grok video generation per second of output, matching the xAI rate
card: parse the request duration (1-15s, upstream default 8s) and compute
cost as per-second price x duration x count. The built-in rate card values
were already xAI per-second prices but were previously charged per video,
undercharging up to 15x with a user-controlled duration.
- Group video_price_* fields are now documented and surfaced as per-second
rates (USD/s); admin UI labels, placeholders and hints updated accordingly.
- Persist video_count/video_resolution/video_duration_seconds on usage_logs
(migration 172) so video billing is auditable, and exempt any row with
video_count > 0 from the image_size check constraint: a video billed via a
token-mode channel price produces billing_mode='token' with image_count=1
and no image_size, which the previous constraint rejected, dropping the
whole billing transaction.
- Only refetch the group in apiKeyWithFreshGroupMediaPricing when the group
object actually looks like it is missing media pricing fields (both media
multipliers zero and all prices nil, impossible for a normally loaded
group), removing a per-usage DB query for groups without overrides.
- Frontend: drop the unused admin.groups.mediaPricing locale block, map
cleared price inputs to null (create) / -1 (update, cleared via backend
normalizePrice) instead of sending "" that failed *float64 unmarshalling,
and align video price placeholders with the text-to-video default model
(grok-imagine-video 0.05/0.07, 1080p only on 1.5 at 0.25).
2026-07-09 15:38:59 +08:00
Wesley Liddick
9ba0fb3084
Merge pull request #3775 from heathermhuang/codex/grok-media-pricing-labels
...
fix: add Grok video pricing controls
2026-07-09 15:03:38 +08:00
wucm667
54859022aa
feat: show used quota in groups list
2026-07-09 11:45:59 +08:00
Heatherm Huang
376e03ded1
fix: update Grok media default rate card
2026-07-08 13:50:49 +08:00
Heatherm Huang
4d702e3234
fix: split Grok image and video pricing
2026-07-08 13:50:49 +08:00
Heatherm Huang
890cc2bb98
fix: clarify Grok media pricing controls
2026-07-08 13:44:09 +08:00
jjaw
6ae5fc31b3
fix(admin): gate scheduler score calculation
2026-07-08 06:58:35 +08:00
Wesley Liddick
4bcb13f77f
Merge pull request #3786 from creamtea47/codex/openai-fast-force-priority
...
add force priority fast policy action
2026-07-07 20:45:45 +08:00
NellPoi
e979990bf9
add force priority fast policy action
2026-07-07 15:27:23 +08:00
Turtle_Li
5494261902
Merge remote-tracking branch 'origin/main' into feature/batch-image-foundation
...
# Conflicts:
# .github/audit-exceptions.yml
2026-07-07 10:53:17 +08:00
Wesley Liddick
913d838770
Merge pull request #3755 from wucm667/fix/subscription-usd-cny-rate-opt-in
...
feat(payment): 套餐编辑页展示订阅 CNY 实扣预览
2026-07-07 08:29:12 +08:00
Turtle_Li
89edba8028
fix: restrict batch image groups to gemini
2026-07-07 04:14:09 +08:00
Turtle_Li
1b07fe821a
merge: sync batch image branch with origin main
2026-07-07 03:27:11 +08:00
wucm667
a23a263513
feat(payment): preview subscription CNY charge in plan editor
2026-07-06 17:52:53 +08:00
Heatherm Huang
a42e9e3fc8
fix: expose Grok image pricing controls
2026-07-06 17:02:28 +08:00
Turtle_Li
616cf17d9e
fix: hide batch image entry without allowed key
2026-07-06 15:03:17 +08:00
shaw
d56e94b875
feat(payment): 订阅 CNY 换算改为独立汇率配置的显式 opt-in
...
- 新增 SUBSCRIPTION_USD_TO_CNY_RATE 配置(1 USD = X CNY,默认 0=关闭),
替代复用 balance_recharge_multiplier 的隐式换算,促销倍率与订阅定价解耦
- 未配置汇率时订阅保持 price 直付的存量行为,存量部署升级零影响
- 前端确认页/原价/手续费/方式限额与后端换算条件严格镜像(rate>0 且币种为 CNY)
- 管理后台新增汇率配置输入(zh/en 文案),checkout-info 透出 subscription_usd_to_cny_rate
- 单测锁定:汇率未配置时不换算、换算使用汇率而非余额倍率、余额订单不受影响、返利仍按 USD price
2026-07-06 14:34:17 +08:00
Turtle_Li
9703ca9d33
merge: sync batch image foundation with upstream main
2026-07-06 13:40:09 +08:00
Turtle_Li
8fab636998
feat: complete batch image workflow
2026-07-06 12:22:04 +08:00
shaw
0fd2e9216d
fix(scheduler): 修复 OpenAI 高级调度器审计发现的正确性与性能问题
...
针对 #3692 合并后审计发现的问题集中修复:
- previous_response_id 剥离条件改为按 call_id 全覆盖校验,
部分可重建的工具续链不再被误剥离(不受开关门控的行为回归)
- 粘性加权回退路径补分组归属校验并清理失效绑定,杜绝跨分组账号泄漏
- 账号列表页:无 OpenAI 账号时跳过分数计算、过滤池限定 openai 平台、
负载批查合并为账号并集一次查询,消除全表扫描与 Redis N+1
- 订阅优先模式下常规池不可用时回退订阅池等待计划,
busy-but-waitable 的订阅账号不再导致请求硬失败
- TopK/权重 DB 覆盖显式受总开关门控,与兄弟子开关语义一致
- 前端未分组 OpenAI 账号回退展示基础分,不再显示 "-"
- ListAllWithFilters 等能力正式进入 AccountRepository/AdminService 接口,
移除匿名接口断言与静默降级;负载批查失败补 warn 日志
- SelectAccountWithSchedulerForCapability 增加显式 previousResponseCanMove
参数,移除 "previous_response_can_move" 魔法字符串哨兵
- 设置写入路径补"基础权重不得全为零"聚合校验;
运行时设置批量读取失败的降级路径覆盖全部键并留痕
2026-07-06 11:43:16 +08:00
linshuboy
f26ca5661e
feat: add OpenAI advanced scheduler controls
...
Related: #1089 , #408 , #123
2026-07-05 17:24:38 +08:00
DaydreamCoding
ebbdc70311
feat(usage): 错误请求对齐用量明细(UI/排序/筛选/列设置)
...
错误请求列表(/admin/usage 错误 tab、Ops 弹窗、用户端 /usage 错误 tab)
对齐用量明细的交互与信息密度。Squash of:
- feat(usage): 错误请求全面对齐用量明细(UI/列序/排序/筛选/列设置/新列)
- refactor(usage): 错误表提取共享徽章工具与 IP 批量工具条,后端排序解析归并 SetSort
- feat(usage): /admin/usage 错误请求新增分类过滤
- fix(ops): 错误列表 phase=upstream 过滤生效,守卫豁免改为显式 opt-in
- fix(ops): 错误列表用户列回退显示已删除 KEY 所有者
- fix(usage): 错误请求状态码排序对齐展示/过滤,筛选项改固定常用码
2026-07-03 23:02:27 +08:00
Wesley Liddick
821399ade1
Merge pull request #3622 from deqiying/feat/subscription-revoke-restore
...
支持恢复已撤销订阅
2026-07-02 17:34:20 +08:00
Wesley Liddick
a32196eedd
Merge pull request #3615 from DaydreamCoding/feat/usage-ip-geolocation
...
feat(usage): add IP geolocation lookup to usage tables
2026-07-02 16:42:06 +08:00
Wesley Liddick
3302146759
Merge pull request #3643 from bestony/feat/admin-group-column-settings
...
feat(admin): add group column settings
2026-07-02 16:40:59 +08:00
Bestony@Homelab
5436d0bf10
feat(admin): add group column settings
2026-07-02 15:04:36 +08:00
Wesley Liddick
a632cb0050
Merge pull request #3569 from xueshiji/main
...
feat(group): 订阅分组新增可选的高峰时段倍率,以支持智谱等coding plan的高峰时段
2026-07-02 14:55:34 +08:00
deqiying
b26dcc3da2
feat(subscription): 支持恢复已撤销订阅
2026-07-01 22:19:21 +08:00
DaydreamCoding
0ff93aca7a
feat: add usage IP geolocation lookup
2026-07-01 21:49:49 +08:00
shaw
60da9ba178
fix(frontend): refine grok icon, palette and i18n
2026-07-01 18:49:33 +08:00
xueshiji
1034f576d7
fix: 高峰倍率全链路透传、计费术语修正与边界处理
...
- 高峰倍率信息透传至可用渠道、支付计划、结算信息等 API,前端
GroupBadge / GroupOptionItem / SubscriptionPlanCard / PaymentView /
SubscriptionsView 统一展示高峰时段与倍率标签
- 修正计费术语:"文本倍率" → "token 倍率",明确高峰倍率同时作用于
token 计费的图片 token,图片按次计费不受高峰影响
- 允许高峰倍率 multiplier=0,支持高峰时段免费策略
- 切换分组类型为 standard 时自动清除高峰倍率配置
- 长上下文计费与标准计费路径改用内部实现,移除冗余中间调用
- 前端高峰倍率相关控件文案改为 i18n
- 新增多组高峰倍率相关单元测试
2026-07-01 17:46:12 +08:00
xueshiji
8b46994dc2
Merge branch 'Wei-Shaw:main' into main
2026-07-01 14:01:03 +08:00
xueshiji
5e9529bb88
Merge branch 'Wei-Shaw:main' into main
2026-07-01 14:00:51 +08:00
DaydreamCoding and Claude Sonnet 5
bdf7ead157
feat(spark-shadow): OpenAI Spark 链接型影子账号
...
背景:gpt-5.3-codex-spark 使用独立于 codex 全局(5h/7d)的配额窗口(数据源是
/wham/usage 响应体的 codex_bengalfox,而非 codex 全局用的 x-codex-* 响应头),且
只能挂在已完成 OAuth 授权的 OpenAI 账号下复用其登录态,不能作为独立账号单独接入。
为此新增“链接型影子账号”(spark shadow account):影子账号本身不持有任何凭据,
通过 parent_account_id 指向母账号,凭据/token/代理透传自母账号并共享母账号的刷新
周期,仅在配额维度(quota_dimension=spark)和用量窗口上与母账号完全独立调度、互不
连坐。
实现:
- 数据模型:migration 154(+154a)给 accounts 表加 parent_account_id /
quota_dimension 列 + 4 条约束(维度合法 / parent⟺非 global 维度一致 / 禁自指 /
FK)+ 2 个 CONCURRENTLY 索引(母账号索引 + 每母账号至多一个影子的唯一索引)。
- 创建:POST /api/v1/admin/accounts/:id/shadow(CreateShadow)—— 一母一影(唯一
索引兜底并发竞态),继承母账号 proxy/分组/并发/优先级(显式传参可覆盖),默认
model_mapping 恒等映射到 spark(拒绝非 spark 模型),母账号必须是真实的 OpenAI
OAuth 账号(非影子)。
- 凭据透传:resolveCredentialAccount 把影子解析回母账号,GetAccessToken / 请求头
/ WS 三条路径统一走此函数;影子自身 Credentials 恒为空(仅允许写 model_mapping),
凭据写入的汇聚点 persistAccountCredentials 对影子早返 no-op,防止误写。
- 调度:parentHealthyForShadow 只看母账号是否仍是 OpenAI OAuth + 凭据/传输是否
可用(active、token 未过期、未处于 401/刷新失败/传输故障导致的临时不可调度冷却),
刻意不看母账号的 global 限流窗口——两条 429 道互不连坐。
- 用量:影子的 codex_5h/7d 走 OpenAIQuotaService.QueryUsage(/wham/usage 的
codex_bengalfox),与母账号走的 WSv2 探测(/responses 头)完全独立的数据源、
刷新节流与 staleness 判定。
- 备份:ExportData 显式排除影子账号(影子不持凭据,通用凭据型导入强制
credentials 非空、无法表达父子链接),按 skipped_shadows 计数提示前端。
- 前端:账号操作菜单新增“创建 Spark 影子”入口,影子行展示回填的母账号信息
(邮箱 / plan / 隐私模式 / 订阅到期 / chatgpt_account_id),批量操作自动跳过
影子账号。
说明:migrations 目录用完整文件名(而非纯数字前缀)标识迁移,故本次新增的
154_account_spark_shadow.sql / 154a_..._notx.sql 与已有的
154_add_ops_system_logs_api_key_id.sql 按序号共存,与目录里 145/151 已有的
先例一致。
测试:新增约 20 个测试文件,覆盖 handler(CreateShadow 校验 / 母账号信息回填)、
repository(影子 round-trip / 一母一影唯一索引 / 迁移 schema)、service(凭据
透传三路径 / 调度母健康门 / 用量窗口来源与刷新节流 / CRS 母账号不变量 / 各类
早返与 fail-closed 场景)及前端组件(账号列表 / 操作菜单 / 用量重置)。
验证(镜像 CI;golangci-lint 首次全量分析耗时过长被跳过,其余全部实测):
- gofmt -l:干净
- go build ./... / go vet ./...:通过
- go test ./... -count=1:全绿(全部包 ok,含 internal/service、
internal/repository、migrations)
- go test -tags integration ./internal/repository/... ./internal/service/...
(真实 Postgres,testcontainers):全绿,含迁移幂等性
(TestMigrationsRunner_IsIdempotent_AndSchemaIsUpToDate)与影子相关全部用例
- pnpm lint:check / pnpm typecheck / pnpm build(真实 vite 构建)/
pnpm vitest run:全绿(124 文件 760 用例)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com >
2026-07-01 12:21:45 +08:00
Wesley Liddick
5f62625ae6
Merge pull request #3577 from heathermhuang/codex/fix-english-ui-cjk
...
fix: remove Chinese strings from English UI
2026-07-01 11:35:04 +08:00