Commit Graph
80 Commits
Author SHA1 Message Date
harukaandClaude Opus 4.8 62d57c02d8 feat(billing): usage_logs 单独记录图片输入 token 与费用
图片编辑/图生图请求的图片输入 token 此前并入 input_tokens/input_cost,
无法对账。拆分上报口径,total_cost 保持不变。

后端:
- CostBreakdown 新增 ImageInputCost;computeTokenBreakdown 将图片输入费用
  从 InputCost 拆出(InputCost 从此仅含文本输入),并纳入 tier 倍率与总额;
  长上下文合并路径同步携带 ImageInputCost
- 迁移 179:usage_logs 新增 image_input_tokens / image_input_cost 列
- UsageLog、insert/query 仓储(含定位参数数组、CTE 列表、扫描顺序)、
  DTO 与 mapper 补齐两列
- openai_gateway_usage 从 usage 与 cost 落库图片输入 token/费用

前端:
- UsageLog 类型、imageUsage 工具(hasImageInputTokens/Cost、textInputTokens)
- 用量表 token 徽标、Token/费用 tooltip 与单价行按图/文输入拆分展示
- zh/en usage.* i18n

测试:
- 新增 gpt-image-2 图片编辑复现用例(复现 #4386 的 $0.016081 期望值)
- 新增 usage 提取器图片输入 token 解析用例(input_tokens_details.image_tokens)
- 更新 doubao 图文分价用例与仓储/契约测试以匹配新的 input/image 拆分口径

相关 #4386。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015wcJTKDddxXSQrepSs3wrU
2026-07-15 10:03:38 -07:00
harukaandClaude Opus 4.8 06e03f467a feat(billing): 渠道自定义定价支持图片输入 token 单价 image_input_price
渠道 token 计费模式此前无法为图片输入 token 单独定价,gpt-image-2
图片编辑等请求的图像输入被按文本 input_price 计费。新增
channel_model_pricing.image_input_price 列及全链路支持。

后端:
- 迁移 178:channel_model_pricing 新增 image_input_price 列
- ChannelModelPricing 新增 ImageInputPrice 字段,repo 读写、校验补齐
- model_pricing_resolver / GetModelPricingWithChannel 映射到
  ImageInputPricePerToken;未配置时归零,由 computeTokenBreakdown
  回退文本输入价(向后兼容,与 image_output_price 的渠道权威规则一致)
- admin / 用户侧定价 DTO 与 model-pricing 自动填充接口补充该字段

前端:
- 渠道定价表单新增「图片输入」价格输入(token 模式)
- API 类型、表单模型、form↔API 换算、自动填充、用户侧模型定价卡展示
- zh/en i18n 标签

相关 #4386。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015wcJTKDddxXSQrepSs3wrU
2026-07-15 09:35:34 -07:00
harukaandClaude Opus 4.8 10cb2ca42c feat(billing): 全局定价解析 input_cost_per_image_token
LiteLLM 定价数据中 gpt-image-2 等模型已含 input_cost_per_image_token
(图片输入 token 单价),但此前未被解析,导致图片编辑/图生图请求的
图像输入 token 被按文本输入价计费。

- LiteLLMModelPricing / LiteLLMRawEntry 新增 InputCostPerImageToken 字段并解析
- GetModelPricing 将其映射到 ModelPricing.ImageInputPricePerToken

计费拆分算术(computeTokenBreakdown)已支持图/文输入分价,本提交补齐
全局定价路径的数据来源。相关 #4386。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015wcJTKDddxXSQrepSs3wrU
2026-07-15 09:23:35 -07:00
benjamin e9fb5983cd fix(billing): 默认关闭 OpenAI 长上下文计费 2026-07-13 23:32:16 +08:00
benjamin 0d9c140bc2 Merge upstream/main into fix/api-double-billing 2026-07-13 11:10:33 +08:00
Wesley Liddick b73d8c3efe Merge pull request #4009 from heathermhuang/codex/fix-recent-grok-issues
fix: expand Grok API, CLI, billing, and setup support
2026-07-13 10:36:11 +08:00
Heatherm Huang 038b25c0b1 fix(grok): resolve recent integration issues 2026-07-13 10:09:53 +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
benjamin 92dcfb5ebc fix(billing): 按账号控制 OpenAI 长上下文计费 2026-07-13 09:47:19 +08:00
superman2003 de28eba3c8 fix(openai): harden GPT-5.6 billing and usage 2026-07-10 15:13:11 +08:00
shaw 0dec1ad292 fix(service): 消除 isOpenAIGPT56Model 重复声明,统一到 openai_model_alias.go
PR #3898 与 #3909 各自新增了同名函数(billing 精确匹配版 / gateway
前缀匹配版),合并后 internal/service 编译失败。保留前缀匹配语义作为
唯一实现:对 normalizeKnownOpenAICodexModel 的输出(gpt-5.6-* 精确
基名)canonicalize 幂等且精确分支命中,计费行为不变;同时保住
gpt-5.6-*-max 等后缀变体的识别。
2026-07-10 14:09:07 +08:00
benjamin 062af81fb5 fix(openai): preserve explicit GPT-5.6 cache write prices 2026-07-10 10:00:47 +08:00
benjamin 383f61d0e9 fix(openai): align GPT-5.6 billing with official pricing 2026-07-10 09:42:31 +08:00
benjamin 4a2b10c94e feat(openai): support GPT-5.6 cache write billing 2026-07-10 09:08:58 +08:00
Wesley Liddick c842c3166c Merge pull request #3847 from heathermhuang/codex/grok-45-official-support
Add official Grok 4.5 support
2026-07-09 16:07:42 +08: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
Heatherm Huang cccba9a82e Add official Grok 4.5 support 2026-07-09 14:26:10 +08:00
Wesley Liddick 4a30397623 fix: prevent channel pricing overrides from mutating shared fallback pricing 2026-07-08 18:37:33 +00: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
shaw 80a229bce5 fix(batch-image): 修复审计发现的计费死锁、状态机与队列原子性缺陷
修复 PR #3768 批量图像 MVP 合并后审计报告中的全部问题:

结算与计费(高危):
- 所有 SETTLEMENT_* 失败(超冻结/计数非法/manifest 冲突/定价缺失/扣费失败)
  统一计入 retry_count 并在耗尽时释放冻结转 failed,消灭 settling 无限
  requeue 导致的冻结余额永久锁死
- 耗尽出口的释放指纹统一为 RequestHash,与 processor/Cancel/recovery 一致;
  release 遇同 request id 指纹冲突视为幂等成功,治愈历史毒消息
- 管理端校验 hold_multiplier >= discount_multiplier,定价快照对存量脏数据钳制
- 释放前校验 per-job hold claim(dedup+归档表),杜绝幻影释放

索引对账(高危):
- provider 输出与提交 custom_id 集对账:未知条目丢弃并记事件,
  漏项补 PROVIDER_RESULT_MISSING 失败行,保证 success+fail == item_count

提交与恢复(高危):
- 提交前转 uploading 并在 provider.Submit 期间心跳刷新 updated_at;
  恢复扫描改为原子复核(FailStaleUnsubmittedBatchImageJob),
  消灭慢提交被误杀退款而上游任务照常计费的孤儿场景
- 上游任务创建成功但本地状态推进失败时,尽力取消上游并清理输入
- recovery 释放失败时入队交由 worker releaseTerminalHold 兜底重试

队列与并发(中危):
- Enqueue(SetNX+LPush)与 Reserve(BRPop+ZAdd)均改为 Lua 原子脚本,
  消灭崩溃窗口导致 job 脱离队列、被 7 天 inflight 键锁死
- 锁冲突按 LockConflictDelay 重新入队(原直接丢弃需等 10 分钟 stale 恢复)
- 处理期间心跳:active zset 续期(ZAddXX 防幽灵成员)+ 锁 TTL 续期
- ReplaceBatchImageItemsForJob 增加 indexing 状态守卫,防掉队 worker 重写账目

存量回归(中危):
- image-only 定价条目(仅图片价无 token 价)恢复 token 计费 fail-closed,
  不再按 $0 计费;图片计费路径不受影响
- 鉴权余额门槛恢复 balance <= 0 语义,MinimumBalanceReserve 不再作硬 403

加固:
- ZIP max_items 钳制到管理员上限;Submit 补齐 Platform==Gemini 校验;
  gemini downloadUri 跟随前做 host 白名单校验
- 批量客户端改用共享 httpclient(拨号/TLS/响应头超时有界)
- 审计点名的忽略错误(MarkDownloaded/SettlementFailed/AppendEvent 等)改为记日志
2026-07-07 18:53:56 +08:00
shaw 6cea1c35bb feat: 适配 OpenAI 新模型 gpt-5.6-sol/terra/luna 2026-07-06 17:34:22 +08:00
shaw 11a3da65c0 fix(group): harden peak-rate config handling and label peak windows with server timezone
Follow-up fixes to #3569 based on code audit:

- Expose server_timezone / server_utc_offset in public settings (and the
  __APP_CONFIG__ injection payload) and label every peak-window display
  with the server UTC offset, so users don't misread the billing window
  as browser-local time
- Unify CreateGroup/UpdateGroup peak-config sanitization via a single
  NormalizePeakRateConfig chokepoint: non-subscription groups always get
  peak fields cleared; unparseable window strings and negative
  multipliers are scrubbed when peak is disabled
- Replace hot-path time.Parse in PeakMultiplierAt with a manual HH:MM
  parser (accept set verified byte-for-byte identical to
  time.Parse("15:04") by exhaustive fuzzing) and reuse it in validation
- Revert the zero-behavior CalculateCost indirection churn in
  billing_service/gateway_service introduced by #3569
- Remove dead GetGroupPlatformMap and the duplicate deref helper in the
  admin handler package
- Share frontend peak formatting via utils/peak-rate.ts, unify the ×N
  label format, and move hardcoded Chinese tooltips to i18n keys
2026-07-02 16:11:07 +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
alfadb b28a223337 fix(openai): 保留 GPT-5.5 Pro Codex 模型名
避免 Codex OAuth 模型归一化把 gpt-5.5-pro 降级为 gpt-5.5。\n\n同时补充 GPT-5.5 Pro 的计费回退与长上下文计费策略,保证保留上游模型名后仍使用现有 GPT-5.5/GPT-5.4 计费规则。\n\n验证:\n- go test ./internal/service/...\n- go build ./cmd/server/
2026-07-01 01:30:42 +08:00
Wesley Liddick 47598462f5 Merge pull request #3401 from StarryKira/fix/issue-3394-fallback-pricing-log-spam
fix: stop per-request fallback-pricing log spam for unknown models (#3394)
2026-06-29 09:19:44 +08:00
Heatherm Huang 39be1ec97f feat: add grok subscription support 2026-06-26 10:36:09 +08:00
harukaandClaude Opus 4.8 7c2fee6c99 fix(billing): dedup fallback pricing warn to stop per-request log spam (#3394)
The "[Billing] Using fallback pricing for model: X" warn was emitted on
every request for any model not in LiteLLM but matched by getFallbackPricing
(e.g. "glm-5.2" substring-matches the "glm-5" fallback price). Via the stdlib
log bridge it is inferred as WARN and persisted to ops_system_logs, producing
tens of thousands of rows/day. It fired even when channel pricing already
overrides the price, and from several call sites (resolver, account-stats
pricing, non-channel billing, admin lookup).

Dedup the warn at the source (BillingService.GetModelPricing) via a sync.Map
keyed by the already-lowercased model name, so each model logs at most once
per process while keeping one audit line. Billing amounts are unchanged.

Also clarify the model/mapping pattern conflict error to state that names are
matched case-insensitively, so an existing entry (e.g. "GLM-5.2") already
covers all case variants and the lowercase variant need not be added — the
behavior the issue mistook for a case-sensitivity bug.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 07:46:52 -07:00
alfadb 262fe1230d feat(billing): 为 doubao-embedding-vision 添加图文差别兜底定价
火山方舟 doubao-embedding-vision 多模态向量化按量付费官方价为文本 ¥0.7/MTok、图片 ¥1.8/MTok,二者不同价。原计费引擎对 embedding 仅记单一 input token、无图片输入档位,无法表达该差别。

变更:
- ModelPricing 新增 ImageInputPricePerToken 字段
- OpenAIUsage / UsageTokens 新增 ImageInputTokens 字段
- extractOpenAIEmbeddingsUsage 解析 usage.prompt_tokens_details.image_tokens
- CalculateCost 拆分文本/图片输入计费;ImageInputTokens 为 0 时走原单价路径,存量 chat/vision 流量行为不变
- getFallbackPricing 新增 doubao-embedding-vision 分支(most-specific-first,覆盖带版本后缀别名),fallback 表填入 $0.098/$0.252 per MTok(汇率 ÷7.14)

测试:新增图文混合/纯文本/图片 token 超额三类用例及定价回退断言;service 包单测与 golangci-lint 全通过。
2026-06-16 19:37:02 +08:00
alfadb 4f5f2788e1 fix(billing): add kimi-for-coding fallback pricing 2026-06-16 19:37:02 +08:00
alfadb c90089c814 fix(billing): address Copilot review feedback
应 PR #3243 review 修正三项问题:

1. 删除 DeepSeek V4 fallback 定价的重复块(cherry-pick 时
   的旧位置 + 新国产 LLM 分段都写了一遍,后写覆盖前写,
   当前值相同所以无 bug,但冗余,未来改一处易漏另一处)。
2. 删除 minimax-m3 匹配中的死代码——modelLower 已经
   strings.ToLower(),'MiniMax-M3' 字面量永远不可能匹中。
3. 测试结构改 *float64 替代 0 sentinel,让 free-tier
   模型(GLM-4.5-Flash / GLM-4.7-Flash)的 0 价能被
   真正断言而非默默跳过;定义内联 floatPtr 辅助函数。
2026-06-16 19:37:02 +08:00
alfadb a4ce73391b feat(billing): add GLM / Kimi / MiniMax fallback pricing for Chinese LLM providers
将 fix/deepseek-fallback-pricing 的 DeepSeek V4 Pro/Flash 定价收编,
并扩展国产 LLM 兜底定价覆盖:

- 智谱 GLM (z.ai 公开 SKU 13 个): glm-5.1 / glm-5 / glm-5-turbo / glm-4.7 /
  glm-4.7-flashx / glm-4.6 / glm-4.5 / glm-4.5-x / glm-4.5-air / glm-4.5-airx /
  glm-4-32b-0414-128k / glm-4.5-flash / glm-4.7-flash
- 月之暗面 Kimi K 系列 4 个: kimi-k2.6 / kimi-k2.5 / kimi-k2-thinking /
  kimi-k2 (K2-0905/K2-0711 官方未保留定价,隐性回退到 kimi-k2)
- MiniMax M 系列 6 个: minimax-m3 (≤512K) / minimax-m2.7 / minimax-m2.7-highspeed /
  minimax-m2.5 / minimax-m2.1 / minimax-m2
- DeepSeek V4 沿用原 fix/deepseek-fallback-pricing 的 entry 移植过来

所有定价数据来自各家官方定价页 (USD/MTok 口径),与现有
Claude/GPT 风格保持一致 (硬编码在 Go 代码里,admin channel 优先)。

匹配策略:长 key 优先 (glm-5.1 优先于 glm-5, k2.6 优先于 k2);
未列出的国产厂商 alias (qwen/doubao/hunyuan) 一律不返回兜底价,
避免误计价——这与 fix/deepseek-fallback-pricing 的白名单语义一致。

数据源注释 (Source URL) 内嵌在每个 initFallbackPricing 分组开头,
便于后续 PR 同步上游价格变化。
2026-06-16 19:37:02 +08:00
alfadb 5a593a511e test(billing): tighten DeepSeek V4 fallback assertions; clarify branch comments
Address copilot-pull-request-reviewer feedback on #2157:

- billing_service_test.go: extend TestGetFallbackPricing_FamilyMatching
  with optional expectedOutput / expectedCacheRead fields and assert
  full Input/Output/CacheRead pricing for all 4 DeepSeek cases
  (v4-pro, v4-flash, deepseek-chat→flash, deepseek-reasoner→flash),
  preventing silent regression to 0 output/cache cost.
- billing_service.go: rewrite the DeepSeek block comment to explicitly
  describe its scope (V4 Pro/Flash + chat/reasoner aliases, no
  unknown-deepseek fallback) and tighten the OpenAI comment to make
  it unambiguous that it only describes the OpenAI/Codex branch
  immediately below it.
2026-06-16 19:37:02 +08:00
alfadb 27e26a3a90 chore: fix gofmt alignment 2026-06-16 19:37:02 +08:00
alfadb c906bf000e feat(billing): add DeepSeek V4 Pro / Flash fallback pricing
Pricing source: https://api-docs.deepseek.com/quick_start/pricing

deepseek-v4-pro:  input $0.435/M, output $0.87/M, cache_read $0.003625/M
deepseek-v4-flash: input $0.14/M,  output $0.28/M, cache_read $0.0028/M

Also map legacy aliases deepseek-chat / deepseek-reasoner → v4-flash.
2026-06-16 19:37:02 +08:00
erio 1e2e8b1d6b fix(billing): channel pricing fully overrides image output token price
When channel pricing is configured, image output token price now
correctly overrides all other sources (LiteLLM, group config).
Add ImageOutputPriceExplicit flag to distinguish intentional zero
price from missing price, preventing fallback to output price.

Affects Gemini, OpenAI inline image gen, and Images API paths.
2026-05-31 22:57:56 +08:00
DaydreamCodingandClaude Opus 4.8 f7f5e33830 feat(quota): user×platform 配额 DB 写聚合 flusher
Redis 同步权威 + DB 镜像,不在进程内维护 delta:
- 写入点 HasUserPlatformQuotaLimit 守卫:无 limit 跳过 Redis 写与持久化
- 累加 usage 的 Lua 在 flusher_enabled 时 SADD 脏集 billing:upq:dirty
- UserPlatformQuotaUsageFlusher 定时 SPOP 脏集 → 批量 HGETALL 读当前窗口 usage 快照
  → BatchSnapshotUsage 绝对值 UPSERT 覆盖 DB(去 SELECT FOR UPDATE 行锁)
  → 失败 SADD 回 / FK(23503)整批丢弃
- flusher 单批 clamp 到 ≤6000,保证一次 flush 只生成一条 UPSERT(单事务原子)
- flusher_enabled 默认 false(降级=旧异步直写 DB)

效果:DB 写连接从 O(QPS) 收敛到 O(副本)。
循环依赖:service 层独立 Snapshot/FK 类型,repository adapter 转换 + %w 映射 FK error。
admin reset/upsert 后失效 cache(脏残留被 flusher 当 MISS 跳过)。

健壮性与可观测性:
- flusher_enabled=false 时 Start 不注册定时器;flush_interval_ms 非法回退 2s
- Readd 回填失败单独计 dirty_lost(不再误记 dirty_readd)并 ALERT;脏集 Readd 补兜底 TTL
- 单 tick 达 max batches 上限仍有积压时记 log
- admin 失效 cache 失败升级为 ALERT(提示 enforcement 可能延迟至 sentinel TTL)
- BatchGet 单条命令失败 / usage 字段损坏均记 log,避免静默以 0 覆写 DB

三态 go vet + 单测/集成测全绿。
已知取舍(默认 flusher_enabled=false 不触发):
- FK 整批丢弃牵连同批正常 key(活跃 key 靠下次 SADD+绝对值快照自愈;Redis 仍权威)
- admin reset/upsert 直写 DB 与 flusher 异步刷存在覆盖竞态:flusher 持旧快照在途时可能覆盖
  admin 刚写值(limit 列不受影响;usage 有 preflight windowExpired 兜底;低频)。彻底消除需 version OCC。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 17:19:15 +08:00
PluviobyteandCursor ed2aac25a6 fix(billing): apply long-context multiplier to cache_creation price
Follow-up to #2816 (already merged): the same long-context pricing
exemption that affected cache_read also applies to all three
cache_creation price fields (standard, 5m ephemeral, 1h ephemeral).
computeCacheCreationCost reads these prices directly from pricing and
never sees the LongContextInputMultiplier that computeTokenBreakdown
applies to inputPrice / outputPrice / cacheReadPrice.

For GPT-5.4 / 5.5 above the 272k threshold, this causes the cache_write
portion of long sessions to be billed at roughly half what it should
be (default multiplier 2.0). Cache writes are conceptually input-side
operations and should share the same long-context treatment as input /
cache_read.

This patch threads an explicit multiplier into computeCacheCreationCost
so the function can be unit-tested in isolation and matches the existing
pattern used for cache_read. computeTokenBreakdown captures the long
context decision once and passes LongContextInputMultiplier when it
applies, 1.0 otherwise.

Adds three regression tests mirroring the #2816 cache_read tests:
- positive: long-context triggered -> cache_creation scaled by 2.0x
- negative: below threshold -> cache_creation stays at base price
- breakdown: 5m + 1h ephemeral prices both scaled when applicable

Refs #2816

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 09:59:58 +00:00
SlientRainyDayandCursor b9509e823a fix(billing): apply long-context multiplier to cache_read price
When session long-context pricing is triggered in computeTokenBreakdown
(e.g. GPT-5.4 / GPT-5.5 above the 272k token threshold), the multiplier
was only being applied to InputPricePerToken and OutputPricePerToken.
The cache_read price was left at its base value, so CacheReadCost was
silently undercharged whenever a long-context session also had cache
hits — which is essentially every long Codex / Claude Code session.

Concretely for gpt-5.4 with 300k cache_read tokens, the bug
under-billed the request by exactly 1x the LongContextInputMultiplier
on the cache portion (e.g. 0.075 instead of 0.150 in the regression
test).

Cache reads are conceptually input-side replays, so they should scale
with LongContextInputMultiplier, matching the treatment of
InputPricePerToken.

Adds two regression tests:
- positive: long-context triggered -> cache_read scaled by 2.0x
- negative: below threshold -> cache_read stays at base price

Fixes #2293

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 07:09:28 +00:00
DaydreamCodingandClaude Opus 4.7 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
2ue bb4c1abe28 Fix image billing size normalization 2026-05-12 15:21:31 +08:00
wucm667 6d69ae87c3 fix(openai): record zero-cost usage for unpriced models 2026-05-09 17:33:35 +08:00
2ue 6faa344916 feat: add OpenAI image generation controls 2026-05-05 03:26:54 +08:00
shaw df722c9a6e fix: remove OpenAI unknown model fallback 2026-05-04 11:43:00 +08:00
shaw 3fe4fd4c35 chore: add model gpt-5.5 2026-04-23 17:28:01 +08:00
erio bbc4aed3d9 fix(openai): 移除已下线 Codex 模型并修复归一化兜底副作用
- backend: 删除 gpt-5 / 5.1 / 5.1-codex / 5.1-codex-max / 5.1-codex-mini / 5.2-codex / 5.4-nano 的内置映射与 DefaultModels 条目
- backend: normalizeCodexModel 默认兜底由 gpt-5.1 改为 gpt-5.4,gpt-5.3-codex-spark 独立保留映射
- backend: 修复 isOpenAIGPT54Model 与 shouldAutoInjectPromptCacheKeyForCompat 对 claude / gpt-4o 的误判(之前依赖 gpt-5.1 作为非 GPT 族的隐式 sentinel,改后需要显式前缀守卫)
- backend: 清理 billing_service 中已不可达的 fallback 价格与 switch 分支
- frontend: 从白名单、OpenCode 配置、预设映射中移除已下线模型
- 同步更新所有相关单测

Refs: #1758, parallels upstream #1759 but adds downstream guard fixes
2026-04-20 22:01:41 +08:00
erio df57d2776b fix(billing): reject rate_multiplier <= 0 on save; clamp negatives to 0 in compute
分组倍率和用户专属倍率在保存时没有校验,0 会触发计费层的 `<=0 → 1.0`
防御条款,结果订阅/余额分组按标准价扣费;完全是沉默地绕过了业务规则。

- 保存校验(admin_service):CreateGroup / UpdateGroup / BatchSetGroupRateMultipliers /
  UpdateUser.SyncUserGroupRates 全部要求 > 0
- 计算层(billing_service):三处 `<=0 → 1.0` 改为 `<0 → 0`;负数按 0 结算,
  避免配置异常被静默按 1x 收费
- 前端:分组倍率 / 用户专属倍率输入 min 统一到 0.001
- 删除未使用的 IsFreeSubscription 方法

测试:新增 billing_service_rate_multiplier_test.go 端到端验证;更新原有锁定
旧 `<=0 → 1.0` 行为的测试。
2026-04-17 22:06:32 +08:00
shaw a789c8c4c7 feat: 支持opus-4.7 2026-04-17 09:37:25 +08:00
erio 62e80c602d revert: completely remove all Sora functionality 2026-04-05 17:11:01 +08:00