Commit Graph
270 Commits
Author SHA1 Message Date
wucm667 b171bb0e4a fix(composite): support CN providers
Extend composite routing, pricing, migrations, and admin options for Kimi, GLM, and DeepSeek.
2026-08-19 13:01:25 +08:00
Randark 7ab6d3db66 test(channel-monitor): quota mode unit/integration/migration coverage
- fetcher:海外/CN coding/CN payg 分派、账号缺失、凭据失效标记、
  TTL 命中与失败不缓存、UsageInfo→tiers 全窗口归一、状态推导矩阵
- quota mode:RunCheck 三分派(quota 单行 / quota_probe 仅挂主行 /
  probe 不变)、配额失败不翻探活状态、校验矩阵、关联账号复核
  (quota 报错 probe 自动解绑)、quota→probe 切换强制重填 key、
  Duplicate 空明文重加密
- settings:channel_monitor_show_quota 缺省关闭 + 仅 "true" 开启
- 迁移内容断言(仿 176 grok 迁移测试)
- repo 集成测试:check_mode/account_id 往返、quota JSONB 回读、
  探活旧行 NULL 兼容(testcontainers PG 实跑迁移 226)
- 修复 Fetch 在 nil receiver 上的 panic(缓存查询先于原 nil 守卫)
2026-08-18 04:51:02 +00:00
Randark 615e6901ea feat(channel-monitor): add quota mode schema (migration 226 + ent)
- 迁移 226:provider CHECK 扩到 8 平台(monitors + request_templates)、
  channel_monitors 加 check_mode/account_id(FK ON DELETE SET NULL)、
  channel_monitor_histories 加 quota JSONB、插入公开设置
  channel_monitor_show_quota(默认 false)
- ent schema 同步:provider 枚举 +4、endpoint 去 NotEmpty(quota 模式存空串)、
  新增 check_mode/account_id 字段、history 加 quota JSON 快照
- domain 新增归一化配额快照类型 MonitorQuotaSnapshot/Tier/Balance
  (放 domain 是因为 ent schema 需要引用,service 会造成 import cycle)
2026-08-18 03:50:01 +00:00
Wesley Liddick b2d1c3859a Merge pull request #5738 from okbexx/fix/codex-identity-snapshot
fix(openai): make Codex convergence identity consistent
2026-08-18 09:57:05 +08:00
Jarl 6793d5ac85 fix(openai): make Codex convergence identity consistent 2026-08-17 20:25:28 +08:00
lyen1688 9f24a55305 功能:支持渠道模型分时倍率定价 2026-08-17 19:45:07 +08:00
Randark e728545382 style: gofmt 迁移测试注释(CI golangci-lint gofmt) 2026-08-17 04:26:22 +00:00
Randark 4b667ccd45 fix(review): 处理 PR #5666 四个阻断项(B1-B4)
- B1: 移除根目录 docker-compose.yml(个人镜像测试产物混入)
- B2: 新增迁移 224 放宽 user_platform_quotas CHECK 至 8 平台,补
  BulkInsertInitial 国产平台集成测试与迁移内容断言测试
- B3: CC/Responses×anthropic 四个上游读循环接入间隔超时泵
  (gateway.stream_data_interval_timeout,默认 180s):上游挂住 SSE
  不发数据也不断连时结束排水/组装、关闭 resp.Body 归还连接池位,
  排水超时仍按已累计 usage 返回(与 messages 主路径同语义)
- B4: 配额/余额探测发起前过 cnValidateProbeURL(与网关转发同一套
  security.url_allowlist 策略),被拒时零出站、API key 不离开本机
2026-08-17 04:07:06 +00:00
lyen1688 cb7b03795d feat: 优化分组用量统计 2026-08-14 22:34:43 +08:00
IanShaw027 b830bc14d6 fix: 长上下文默认保持开启,并与 OpenAI 账号开关取交集
迁移默认 false 会让存量分组静默丢掉 ≥200k 阶梯与渠道多档价。
OpenAI 路径传入 Group 后,账号级 openai_long_context_billing_enabled 被顶掉。

- 列默认 TRUE,并对存量行回填
- 分组价卡不再手填 token 区间,勾选走官方/预设阶梯
- 分组开关与账号开关 AND;价卡 JSON 损坏时打 warn
2026-08-13 08:38:10 +08:00
IanShaw027 f3d9491071 feat: 分组支持逐模型定价,并可关闭长上下文阶梯
运营需要按分组覆盖渠道/内置价,且部分套餐不应自动吃 200k 倍率。
原先只能改渠道价卡,分组侧只剩 Voice 三列。

- groups 新增 model_pricing / long_context_pricing_enabled,解析链改为 Group → Channel → 内置
- 关闭长上下文时 token 模型只取最低档;video 按秒计费可写进同一价卡
- 回退价对齐官方卡:4.5 缓存 $0.30、4.3/imagine/audio/search 默认值一并校正
2026-08-13 07:49:08 +08:00
shaw d92edc01be Merge origin/main into feat/channel-monitor-v2-ops-ui
Resolves three conflicts, all of the "both branches appended to the same
block" shape. Every one is resolved as a union of both sides; nothing from
either parent is dropped.

- handler/admin/setting_handler_update.go: keep ChannelMonitorHideThroughput
  (V2) alongside GrokDefaultTextModel / GrokCrossClientModelMapEnabled /
  GrokDefaultBaseURLMode (#5408). UpdateSettings writes every key on each
  save, so dropping either side would reset those settings to zero values.
- service/domain_constants.go: keep SettingKeyChannelMonitorHideThroughput
  and the three SettingKeyGrok* constants.
- repository/migrations_runner.go: keep the 195 checksum rule (V2) and the
  218/219/220 rules (#5408).
2026-08-09 12:11:35 +08:00
IanShaw027 7eb1310701 fix(grok): close free-by-default billing and related review blockers
H1/H2: bill search and voice with code defaults when group prices are
nil (explicit 0 remains free); bump API key auth snapshot to v19 and
refresh incomplete media/search/audio projections.

M1–M6: free-quota soft gate fails open on cache miss with background
refresh and 60s default TTL; correct password_auth config docs; default
cross-client model map to true (→ grok-4.5); audit /tts and /web_search;
exclude composite from migration 220 video-price clears; never let a
search surcharge mask token pricing failures.
2026-08-08 14:39:22 +08:00
IanShaw027 825f9c78d5 fix(channel-monitor-v2): default mode v1 and gentle adaptive backfill
Default channel_monitor_mode to v1 (opt-in V2) so upgrades keep active
probes; existing explicit v2 rows are left alone via ON CONFLICT DO NOTHING
plus migration checksum compatibility for already-applied 195.

V2 first-enable backfill no longer compresses ticks to 5s or uses 24h
chunks. Each tick does recent overlap plus at most one historical chunk
with depth-based ceilings (2h/4h/6h), adaptive grow/shrink, and failure
backoff. Error request_id dedup is bounded by a 90-minute lookback so
ops_error_logs is not scanned for full history.

Also align hide_throughput parse default with privacy-preserving public
runtime (missing key → true).
2026-08-08 13:59:11 +08:00
IanShaw027 1f58e25ab3 Merge upstream/main into feat/grok-complete-integration
冲突集中在 chat completions / messages 两条 Responses 转发路径:
upstream 给 OpenAIForwardResult 增加了 UpstreamResponseModel 与
UpstreamResponseModelConflict(配套 beginUpstreamResponseModelObservation
观测器),本分支在同样位置把返回值改成了具名变量以便挂 Grok 原生搜索计数。
两侧不互斥,合并结果同时保留上游的响应模型观测字段与 Grok SearchCount 逻辑。

frontend/pnpm-lock.yaml 取 upstream 版本:package.json 与 upstream 完全一致,
本地差异只是 pnpm install 的重解析噪音。
2026-08-08 11:12:56 +08:00
IanShaw027 07b46e93e4 fix(grok): 修正 voice 路由推导、视频价归一化与门禁缓存驻留
- custom-voices endpoint 改由匹配到的路由模板推导(c.FullPath())。
  原实现按请求 URL 字面后缀判 /audio,voice_id 恰为 "audio" 时
  GET /custom-voices/audio 会被改写成 custom-voices/audio/audio,
  把档案查询变成音频下载。补 voice_id="audio" 的路由推导测试。

- NormalizeVideoModelPrices 不再把无法识别的分辨率静默折算成 480p:
  新增 LookupVideoBillingResolution 报告未知档位,配置解析路径丢弃并告警,
  运行时计费仍走 OrDefault 兜底。model/tier 两层遍历改为排序遍历,
  多个别名收敛到同一 family 时结果不再随 Go map 顺序漂移,冲突单价告警。

- grok free quota 软门禁缓存新增过期淘汰。条目按 account_id 键控且只写不删,
  账号下线后会驻留至进程结束;淘汰只挂在已受 TTL 约束的查询路径上,
  不影响缓存命中热路径。

- 迁移 220 清空非 Grok 分组视频价前先落快照表 groups_video_price_backup_220,
  原 UPDATE 不可回滚。

- 简化 grok_search_count 两处等价冗余的事件类型分支。
2026-08-08 11:02:22 +08:00
IanShaw027 9f3ee38d4e fix(channel-monitor-v2): preserve migration checksums and privacy defaults 2026-08-08 08:55:59 +08:00
IanShaw027 0d98176c59 fix(channel-monitor-v2): correct aggregation privacy and backfill 2026-08-08 01:59:44 +08:00
IanShaw027 165b072908 fix(grok): gateway media/voice routing, models, and status UI polish
Align gateway Grok media/voice paths and model lists, harden upstream failure
and quota handling, clear non-Grok video generation config migration, and polish
temp-unsched/status indicators with model whitelist updates.
2026-08-08 01:07:27 +08:00
Brisbanehuang db0bff82c7 feat(usage): audit upstream response models
(cherry picked from commit 839036224f795c8ee5dc6718a2a14372a45eea44)
2026-08-07 09:40:11 -04:00
IanShaw027 79df1647d4 feat(grok): 账单绝对金额、调度阈值 UI、搜索/Voice 计费与 /v1/web_search
- BillingSummary 输出 prepaid/monthly_used/on_demand 绝对金额,并映射官方 7d/30d 进度条
- 账号编辑页支持 credentials.account_scheduling_threshold 覆盖;Settings 文案细化
- groups.search_price_per_1k + 管理端/缓存全链路;SearchCount/AudioUsage 请求级计费
- Voice TTS/STT/Realtime 成功路径 RecordUsage;独立 /v1/web_search 原生 Grok 搜索
2026-08-07 15:52:55 +08:00
IanShaw027 99ad01f6de feat(grok): 网关 Voice TTS/STT/Realtime 与分组音频定价
- 中继 xAI Voice HTTP(/tts /stt /custom-voices)与 Realtime WS(/realtime)
  仅 Grok 分组可用;账号选调度沿用 chat 能力,不依赖创作中心
- Voice URL 固定走 api.x.ai(CLI proxy base 自动回落)
- 分组级 audio_realtime / TTS / STT 单价:schema + migration 218 +
  admin API + GroupsView 表单与 i18n(无创作中心 UI)
2026-08-07 15:08:39 +08:00
IanShaw027 eb6c9663e7 feat(grok): 视频按模型族配置每秒单价,并补齐管理端映射设置
分组新增 video_model_prices(JSONB);计费优先模型×分辨率覆盖,
其次旧分辨率三列,最后官方按模型族默认价。同步补齐 admin 设置
中的 grok_default_text_model / 跨客户端映射开关,并保持
grok-imagine-video-1.5 请求模型 identity 不被静默改写。
2026-08-07 12:44:08 +08:00
IanShaw027 a58048ac32 feat(channel-monitor-v2): 添加被动监控聚合表与模式相关迁移
引入 V2 事实表/固定 rollup、模式设置、忽略错误类、健康阈值、权限与
默认忽略/缓存阈值,以及用户端隐藏吞吐速率的系统设置键。
2026-08-07 11:05:32 +08:00
Brisbanehuang 20ad5ec506 feat(scheduler): per-group profit control for token account admission
Group pricing (rate multiplier, peak windows, per-user overrides) and
account cost (accounts.rate_multiplier) already live side by side, but
nothing stops the scheduler from handing a request to an account whose
cost multiplier exceeds what the group's pricing can profitably serve.
Add an opt-in per-group profit gate that filters scheduling candidates
by a margin rule, while ordering, scoring, stickiness and breakers keep
working unchanged among qualified accounts.

Admission rule: an account qualifies iff U <= D * (1 - min_margin -
safety_buffer) within a small relative epsilon, where U is
accounts.rate_multiplier (0 is legal; missing/negative/NaN/Inf are
conservatively rejected as invalid) and D is the requester's effective
downstream multiplier (user-group override ?? group default, times the
group peak factor) frozen at the request's pricing instant.

- groups gain profit_control_enabled / profit_min_margin /
  profit_safety_buffer (migration 191); the durable auth-cache
  invalidation trigger additionally watches the profit and pricing
  columns (migration 192) so out-of-band group edits cannot leave
  stale auth snapshots; GetByKeyForAuth explicitly projects the new
  columns and the API-key auth snapshot version is bumped to force a
  refresh of pre-existing snapshots
- request-level pricing instant: token entry points install pricingAt
  into ctx; the profit threshold D and the RecordUsage peak factor
  read the same instant, so one request never changes price mid-flight
  across waits/retries/failover (media and unwired paths keep the
  existing record-time semantics)
- the gate covers token requests on openai, anthropic, gemini, grok
  and antigravity groups: OpenAI-family handlers via
  WithOpenAIRequestPricingContext (responses incl. WS bridge, chat
  completions, messages, embeddings, alpha search), the shared gateway
  via WithGatewayTokenRequestPricing (messages, chat completions,
  responses, gemini model actions); composite groups cannot enable it
  directly; image/video/models/usage/count_tokens stay ungated and an
  explicit image-generation intent suppresses the gate end to end
- post-slot recheck: after a slot is acquired the account is re-read
  via SchedulerSnapshotService.GetAccount (scheduler cache, then DB;
  only when both fail the check fails open with WARN + metric); a
  vetoed account releases its slot and joins the request's exclusion
  set for reselection; sticky bindings are written only after the
  final check passes, and an over-threshold sticky account is skipped,
  not deleted, so it comes back once its rate recovers
- sticky-session cache contract: GatewayCache.GetSessionAccountID now
  returns ErrStickySessionNotFound on a miss (mapped from redis.Nil in
  the repository implementation, mirroring ErrRefreshTokenNotFound) so
  the profit sticky path can distinguish "no binding yet" from a real
  read failure without importing the cache driver in service code
- cross-group re-entry (composite parent -> member group) resolves the
  gate against the member group and clears a stale parent gate instead
  of letting a foreign threshold veto accounts
- per-platform/group activity counters (installs, threshold vetoes,
  invalid-rate vetoes, refresh failures) for observability
- admin UI: profit-control section on the five platforms' group forms
  with percent input, validation and platform-switch reset; group
  create/update/duplicate normalize and validate the config at a
  single choke point
- cmd/profit-preview: offline what-if tool that replays the production
  admission semantics over an exported config/account/override/model
  dump, reports per-model admitted-account counts under the default
  and the worst-case (lowest user override) D, and surfaces probe-sync
  staleness as warnings without affecting admission

Tests: service unit coverage for gate resolution/veto/threshold
epsilon/pricing instant/suppress marker/scheduler filtering and
post-slot recheck (incl. -race on the profit surface), unit-tagged
handler slot-recheck and capability-mapping regressions, sqlmock and
real-PostgreSQL integration regressions for the GetByKeyForAuth
projection and the migration-192 trigger watch list, API contract
update, and frontend specs for the five-platform form helpers.
2026-08-01 22:39:31 +08:00
Zhixuan Jiang cc62979aa7 feat: add passkey authentication 2026-07-26 09:50:28 -04:00
shaw bc3acd6e28 fix(auth): 收紧注册别名查重(根点绕过 / 误拒 / 无界扫描 / 并发竞态)
对 #4814 的审计跟进修复:

- 域名尾随点绕过:user@gmail.com. 的域名不在 gmail 家族名单内,点号折叠与
  googlemail 归一被整体跳过,别名刷号原样可复现。归一化入口统一去掉 FQDN 根点。
- 误拒合法用户:剥 "+后缀" 缺空串守卫,+alice@ 与 +bob@ 都折叠成 @domain,
  该域后续 "+x@" 注册会永久 EMAIL_EXISTS 且无自助恢复。改为仅当 "+" 不在首位时剥离。
- 无界不可索引全表扫描:原实现按 LOWER(email) LIKE '%@domain' 把整域邮箱读进内存,
  且挂在公开未鉴权的 send-verify-code 上。改为按去点邮箱
  REPLACE(LOWER(TRIM(email)), '.', '') 做等值 + "local+%@domain" 前缀探针并带 LIMIT,
  新增同表达式的部分索引(migrations/190)。TRIM 口径与既有精确匹配一致,
  历史带首尾空白的行同样命中;LIKE 元字符转义,% 与 _ 不会扩大匹配面。
- 并发竞态:注册改走 CreateWithEmailAliasGuard,在邮箱唯一性锁上追加收件箱身份锁并在
  锁内复查,避免同一收件箱的多个别名变体同时通过服务层前置查重。管理员建号仍走
  Create,不受别名限制。
- 能力断言静默 fail-open:别名查重方法上提到 UserRepository 端口(编译期强制),
  移除可选接口类型断言与静默降级分支。
- OAuth 邮箱注册的两条建号路径(同样发放注册赠额)纳入同一查重口径;邮箱换绑/绑定
  不纳入,否则用户把邮箱改成自己收件箱的别名会被误拒。
2026-07-25 19:40:53 +08:00
shaw 5374ce2a0f Merge remote-tracking branch 'origin/main' into feature/openai-live-gateway 2026-07-25 15:16:05 +08:00
shaw 7acc13a29b fix(live): 租约丢失终止会话并补齐过期时的 usage log
三处功能修复(审计发现):

1. 租约续租失败按会话终结处理。RefreshLiveLease 的 Lua 在 leaseID 被 GC 后不会
   重新 ZADD,重连拿不回并发槽;原先把 ErrLiveUnavailable 当临时错误交给 observer
   重连,会让会话以约 1 秒一轮的节奏空转到 ExpiresAt(最长 60 分钟),期间持着
   上游 WS 连接却不计入账号/用户/API Key 的任何并发限制。

2. observer 因过期放弃时补写 usage log。waitForLiveObserverRetry 原先把过期判定
   混在重试条件里并返回 false,直接 return 绕过了 observeLiveCall 循环顶部的过期
   分支,导致该路径既不写 usage log 也不释放租约(静默结束)。改为只判控制权归属,
   过期交回循环顶部 finalize。

3. 把两处重复的三项终止判据抽成 liveSessionEnded,消除 ProxyLiveSideband 与
   observeLiveCall 之间的判据漂移风险。

迁移改名 186/187 -> 188/189:原编号会成为第三个 186,且 187 与已合入 main 的
#4801 的 187_add_usage_log_session_id.sql 撞号。文件名即迁移主键,功能无害但易误读。

新增两个测试均经变异验证(去掉修复后会失败)。
2026-07-25 15:15:59 +08:00
song e6eb23eaac feat(openai): add Live gateway support 2026-07-25 12:50:46 +08:00
Edison42 1c0cb24c7e feat(usage): persist client session identifiers 2026-07-24 01:22:34 +08:00
Wesley Liddick 2c76506e07 Merge pull request #4734 from wjx2951874/feat/alipay-mobile-precreate-deep-link
feat(payment): add mobile Alipay precreate deep link
2026-07-23 14:06:18 +08:00
Wesley Liddick fbc88edf90 Merge pull request #4750 from heathermhuang/codex/fix-simple-default-grok-image
fix(simple-mode): enable images for auto-created Grok default
2026-07-23 11:19:20 +08:00
Heatherm Huang a008b63c16 Add composite group route registry 2026-07-23 09:20:18 +08:00
Heatherm Huang 33d694b89b fix(simple-mode): enable images for auto Grok default 2026-07-23 00:08:23 +08:00
wjx2951874 7914433011 feat(payment): add mobile Alipay precreate deep link 2026-07-22 19:18:04 +08:00
zhaozewu 6c93f01c97 fix(groups): tighten reasoning policy
Remove unsupported none handling, align the auth cache version with the current baseline, consolidate the unshipped migrations, and update the public API contract.
2026-07-21 11:16:04 +08:00
zhaozewu 6af622c340 feat(groups): add OpenAI reasoning policy
Persist reasoning ceilings and exact mappings for OpenAI groups, enforce them across HTTP and WebSocket forwarding, and invalidate cached auth snapshots.
2026-07-21 11:02:43 +08:00
benjamin b92bbf0299 fix: 过滤入口拒绝日志并强化鉴权边界 2026-07-18 00:11:18 +08:00
Wesley Liddick 8bfbc5ca99 Merge pull request #4485 from Sub2API-Devs/dev
feat(security-audit): 新增 OpenAI 兼容提示词审计能力与安全审计控制台
2026-07-17 16:15:26 +08:00
mt21625457 ac685ccaf5 feat(security-audit): persist full prompts on audit events and polish event review UI
- Add prompt_audit_events.full_prompt (migration 182) so admins can review
  the exact unredacted prompt that triggered a finding; blocking mode writes
  it from the snapshot, async mode reconstructs it from the Redis scan
  payload so jobs rows stay redaction-only
- Event detail API returns full_prompt (list endpoint stays lean); text is
  NUL-stripped and capped at 65536 runes
- Detail dialog shows the full prompt in a scrollable pane with fallback to
  the legacy redacted preview; page copy updated to match the new behavior
- Rework filter deletion into a dedicated dialog with time-range presets and
  criteria-change preview invalidation; localize decision/risk/category
  labels across the events workspace
- Fix pre-existing i18n message-compile spec by declaring the
  @intlify/message-compiler dev dependency
2026-07-17 14:38:10 +08:00
mt21625457andCursor 0f7f8a317e fix(security-audit): close prompt-audit bypass and privacy gaps
Stop WebSocket follow-up turns from reusing a request-wide audit cache, scan
client-controlled instruction fields, fail closed on stale weaker configs, and
tighten preview/SSRF controls including persisted request stage.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-17 08:46:57 +08:00
mt21625457 d11bdb13f5 feat(security-audit): add OpenAI-compatible prompt auditing 2026-07-17 00:39:39 +08:00
yan9651688 9fc006546c Make repeated group setup safer
Admins often recreate groups with the same pricing, routing, and account membership. A server-side duplicate creates an inactive copy for review, preserves eligible account priorities, and recovers ambiguous retries without creating extra groups.

Constraint: Group has no neutral JSON metadata field for durable operation recovery
Constraint: Model routing references account IDs, so copied configuration requires matching bindings
Rejected: Rebuild from the list response | it omits configuration and account priority details
Rejected: Store operation identity in business configuration | it would pollute real group settings
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep duplicated groups inactive until an administrator reviews the copied configuration
Tested: Go unit and full tests, go vet, integration-tag compile, frontend Vitest, lint, typecheck, production build, and Playwright duplicate flow
Not-tested: PostgreSQL container integration locally because Docker is unavailable; CI will execute the database-backed suite
2026-07-16 18:18:28 +08:00
shaw 0ddd58aaf9 feat(security): 操作审计日志 + 会话IP/UA绑定 + 敏感操作 step-up 2FA
应对管理员访问凭证失守导致的数据外泄风险,新增三层防护:

审计日志(admin-only 可见,用户不可见)
- 新增 append-only audit_logs 表(migration 180)+ 异步批量写入 + 保留期清理
- 审计中间件挂在 admin/user/auth/admin-payment 组认证之后:记录所有变更类
  请求 + 白名单敏感读取(账号/代理导出、备份下载、admin/user API key 读取)
- 请求头凭证首尾掩码;请求体 JSON 递归脱敏(api_key/password 等擦除,base_url
  保留以便追责);非 JSON body 不入库
- 无单条删除;全量清空需现场 TOTP 校验、拒绝 admin API key、未启用 2FA 不允许,
  清空后同步写入留痕记录

会话 IP/UA 绑定(默认开启,可在系统设置关闭)
- JWT 携带 session id + IP/UA 指纹哈希;IP 或 UA 任一变化即撤销会话家族并要求
  重新登录;旧 token 无指纹时放行以平滑升级

敏感操作 step-up 2FA(sudo 窗口 15 分钟)
- 账号/代理导出、DB 备份创建/下载、S3 目标修改要求近期 TOTP 二次验证;admin API
  key 一律拒绝;前端 useStepUp 组合式 + TotpStepUpDialog 弹码后自动重试
- API key 查看按需求暂不加强管控

前端:新增 /admin/audit-logs 操作日志页面(筛选/详情/2FA 清空)、侧边栏入口、
step-up 弹窗接入导出与备份流程、安全设置项(绑定开关 + 日志保留天数)、zh/en i18n
2026-07-16 13:47:50 +08:00
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
turingcatandClaude Fable 5 705da4f610 feat(payment): 补充订阅套餐币种字段的 SQL 迁移文件
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 16:59:00 +08:00
superman2003 0a64a6d8ce feat(monitor): support Grok channel health checks 2026-07-14 12:24:42 +08:00
Wesley Liddick 41c71a1528 Merge pull request #4216 from bestony/agent/devbox-coding/3ff3c99d
feat(ops): add Host filtering to system logs
2026-07-14 10:13:40 +08:00