4474 Commits
Author SHA1 Message Date
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 等后缀变体的识别。
v0.1.150
2026-07-10 14:09:07 +08:00
Wesley Liddick 8b96acde97 Merge pull request #3898 from Arron196/feat/gpt-5.6-cache-billing-stats
feat(openai): 支持 GPT-5.6 系列缓存写入计费与统计
2026-07-10 13:57:29 +08:00
Wesley Liddick 5c9748cef9 Merge pull request #3922 from fengshao1227/fix/user-breakdown-request-type-filter
fix(admin): GetUserBreakdown request_type 筛选使用字符串解析
2026-07-10 13:56:40 +08:00
Wesley Liddick 312ab1f0bd Merge pull request #3926 from fengshao1227/fix/ws-passthrough-reasoning-effort-candidates
fix(usage): WS passthrough effort 提取补入映射后模型候选
2026-07-10 13:46:25 +08:00
li ea9f40b63f fix(frontend): UserBreakdownParams.request_type 类型从 number 改为 UsageRequestType 2026-07-10 12:38:21 +08:00
li b9b013a088 fix(usage): WS passthrough effort 提取补入映射后模型候选
Fixes #3924
2026-07-10 11:56:47 +08:00
li dda8f78733 fix(admin): GetUserBreakdown 使用 ParseUsageRequestType 解析 request_type
Fixes #3920
2026-07-10 11:43:44 +08:00
Wesley Liddick ddb1a210ce Merge pull request #3912 from superman2003/fix/audit-concurrency-and-recovery
fix: harden billing concurrency and payment recovery
2026-07-10 11:38:45 +08:00
Wesley Liddick 301c99a26c Merge pull request #3916 from Wei-Shaw/fix/reasoning-effort-model-candidates
fix: effort 提取改用模型候选列表,修复后缀模型用量元数据丢失
2026-07-10 11:16:35 +08:00
shaw c3ae5fc3c5 fix(usage): effort 提取改用模型候选列表,修复后缀模型元数据丢失
#3909 将 effort 提取的模型参数改为 firstNonEmpty(upstreamModel, ...),
而 OAuth 的 normalizeCodexModel 会剥掉模型 effort 后缀
(gpt-5.4-xhigh -> gpt-5.4),导致后缀式模型且 body 无显式
reasoning 字段的请求在 usage 元数据中丢失 effort。

extractOpenAIReasoningEffortFromBody/extractOpenAIReasoningEffort
改为接受模型候选变参:显式 effort 的 max 保留判定沿用第一个非空
候选(映射后模型),后缀推导回退依次尝试每个候选(原始模型名兜底)。
纯元数据修复,不改变任何转发行为。
2026-07-10 11:09:06 +08:00
Wesley Liddick cddcf49044 Merge pull request #3884 from CHOS1N11111/codex/add-parallel-tool-calls-compat
Add parallel_tool_calls compatibility mapping
2026-07-10 11:01:03 +08:00
Wesley Liddick 9389503c56 Merge pull request #3913 from fengshao1227/fix/en-locale-missing-keys
fix(i18n): 补齐 en 语言包 overview 和 resources 缺失 key
2026-07-10 10:59:49 +08:00
Wesley Liddick 72ef0b3884 Merge pull request #3909 from githubbzxs/fix/gpt56-max-compact
fix: support GPT-5.6 max reasoning effort
2026-07-10 10:57:35 +08:00
superman2003 fc66a30ffc fix: harden billing concurrency and payment recovery 2026-07-10 10:56:49 +08:00
li e984b4e2e1 fix(i18n): 补齐 en 语言包 overview 和 resources 缺失 key
Fixes #3909
2026-07-10 10:45:44 +08:00
Wesley Liddick 066a85949a Merge pull request #3905 from fengshao1227/fix/codex-client-version-bump
fix(openai): 升级 Codex 客户端版本至 0.144.1,修复 gpt-5.6-luna 404
2026-07-10 10:43:51 +08:00
Wesley Liddick 3099362074 Merge pull request #3906 from Wei-Shaw/fix/compact-sse-raw-output-item-preservation
fix(compact): SSE→JSON 保留 raw output_item.done 并为 unary 等待补下游心跳(修复 #3887)
2026-07-10 10:41:02 +08:00
psyche 80b3d4c1f8 fix: 兼容 GPT-5.6 max 推理强度 2026-07-10 10:39:16 +08:00
shaw 000f6dc655 fix(compact): 终态 output 非空但缺 compaction 时从事件流补入(146 等价性收尾)
146 纯流式透传下 Codex 只从 raw output_item.done 收集 item,无论终态
output 形态如何都能拿到 compaction;SSE→JSON 提取链路此前仅在终态 output
为空时修补。补齐最后一处不等价:compact 请求终态 output 非空但缺
compaction、事件流中存在(done 优先 added 兜底)时以 raw JSON 追加。
门控:仅 compact 路径 + 仅缺失时触发,已含 compaction 或非 compact
请求逐字节不变。

Refs #3887 #3777
2026-07-10 10:25:09 +08:00
benjamin 5c15d32ff7 test(repository): stabilize expired lock reconciliation 2026-07-10 10:18:50 +08:00
shaw ae9a01d852 fix(compact): 二轮审计加固——心跳字节不得污染 failover 判定与并发写安全
对首轮修复的对抗式审计发现并修复以下问题:

1. failover 判定污染(真实回归风险):handler 以 "Forward 前后
   c.Writer.Size() 是否变化" 判定响应是否已写出并据此放弃换号。心跳注释
   字节会使该判定恒真,compact 请求一旦在上游等待期间发过心跳,上游
   429/5xx 将不再 failover。新增
   OpenAICompactKeepaliveAdjustedWrittenSize(扣除心跳字节、互斥锁下
   一致读取、仅心跳字节归一化为未写哨兵 -1),快照、failover 比较与
   openAIForwardErrorAlreadyCommunicated 三处判定统一改用该口径;无心跳
   请求完全等价于原 c.Writer.Size()。

2. 并发写竞争:心跳 goroutine 与未被显式拦截的写回路径(Forward 内部
   本地拒绝等)存在 ResponseWriter 数据竞争。StartOpenAICompactSSE-
   Keepalive 现将 c.Writer 替换为 openAICompactKeepaliveWriter:写侧
   方法(Header/Write/WriteString/WriteHeader/WriteHeaderNow/Flush)
   先在互斥锁下停拍,读侧(Status/Size/Written)仅加锁不停拍——任何
   请求侧响应构造与心跳从构造上互斥,热路径状态读取不误杀心跳。

3. 语义拦截补齐:rejectIfCyberSessionBlocked(在用户槽位长等待之后
   执行的直接 c.JSON)与 writeOpenAIFastPolicyBlockedResponse 在心跳
   提交后降级为 response.failed 终止事件;未提交时先停拍再写 JSON,
   状态码语义不变。失败事件 errType 参数化(permission_error 等)。

4. reconstruct 混合形态:done 事件存在但 compaction 只在
   output_item.added 中时也要补入;done 已含 compaction 时跳过 added,
   避免无 id 可去重时收集两份(Codex 要求恰好一个)。

5. 观测性:logOpenAIRemoteCompactOutcome 对心跳提交后的失败(wire 200)
   以 GetOpsStreamError 纠正 outcome,不再误记 succeeded。

新增 5 个测试:failover 口径不变式、包装器停拍语义(-race)、fast
policy 提交前后两态、混合 done/added 形态(含去重)。

Refs #3887 #3777
2026-07-10 10:18:16 +08:00
benjamin 0a5f34a2ef fix(openai): recognize Windows websocket resets 2026-07-10 10:11:21 +08:00
benjamin 062af81fb5 fix(openai): preserve explicit GPT-5.6 cache write prices 2026-07-10 10:00:47 +08:00
shaw 2cffe1cf5f fix(compact): SSE→JSON 保留 raw output_item.done 并为 unary 等待补下游心跳(修复 #3887)
#3887 报告 v0.1.149(已含 #3880 桥接修复)remote compact 仍失败且持续
计费。核实为 #3880 明示的两个遗留:

1. 上游对 unary compact 返回 SSE 且 compaction item 只出现在 raw
   response.output_item.done、终态 completed.response.output 为空
   (#3777 实录形态)时,reconstructResponseOutputFromSSE 只累加
   text/function_call/reasoning 三类 delta,compaction item 被丢弃,
   桥接合成 0 个 output_item.done,Codex 报 "expected exactly one
   compaction output item, got 0" 后盲目重试,每次重试重新消耗上游
   compact 配额。
2. 桥接为全缓冲写回:上游 unary 完成前(大上下文可达数分钟,且上游
   处理期间不发送任何字节)下游连响应头都收不到,反向代理
   (Nginx/Cloudflare Tunnel)空闲超时掐断连接同样触发盲重连
   (同类问题见 #2243/#2976)。

修复:

- reconstructResponseOutputFromSSE 优先以 raw JSON 逐字节收集
  output_item.done item(协议上的最终完整形态),不经窄结构体,
  encrypted_content/summary/opaque 等 compact 专属字段全部保留;
  无 done 事件时退回收集 output_item.added 中的 compaction 类 item;
  两者皆无才回到原 delta 重建。path-based v1 JSON 写回同样受益。
- 新增 openAICompactSSEKeepalive:body-signal 客户端流式 compact 在
  上游等待期间按 gateway.stream_keepalive_interval 向下游写 SSE 注释
  行心跳(eventsource 解析层直接忽略)。首拍延迟一个间隔,快速失败
  仍走 JSON+状态码;首拍后状态码固化为 200,桥接/错误链路
  (writeOpenAICompactSSEBridge、errorResponse、
  handleStreamingAwareError、ensureForwardErrorResponse、
  writeOpenAINonStreamingProtocolError)统一降级为 response.failed
  终止事件并标记 ops 流内错误。
- API-key 账号的 compact 上游请求也强制 accept: application/json
  (#3777 期望行为 4;透传白名单原会放行客户端的 text/event-stream)。

测试:#3777 实录形态经 handleSSEToJSON / 透传 / path-based 三条链路
的修补断言;raw-done 优先不与 delta 重复;added 回退门控;心跳提交、
提交后 2xx 续写、提交后失败降级、未提交行为不变;-race 通过。

Fixes #3887
Refs #3777 #3875 #3880
2026-07-10 09:56:56 +08:00
li 657c4f97d9 fix(openai): 升级 Codex 客户端版本至 0.144.1,修复 gpt-5.6-luna 404
Fixes #3895
2026-07-10 09:56:33 +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
github-actions[bot] 12d811bd76 chore: sync VERSION to 0.1.149 [skip ci] 2026-07-09 14:57:53 +00:00
CHOS1N ad8afc8a2e Add parallel_tool_calls compatibility mapping
Preserve Chat Completions parallel_tool_calls when converting requests to the Responses API, and map Responses parallel_tool_calls back when falling back to Chat Completions upstreams.

Cover both true and explicit false values so clients can disable parallel tool calls without the field being dropped by omitempty.
2026-07-09 22:52:35 +08:00
Wesley Liddick dd1a116f48 Merge pull request #3881 from Wei-Shaw/feat/version-rollback
feat: 版本徽章新增近3个历史版本在线回退与手动回退指引
v0.1.149
2026-07-09 22:39:41 +08:00
Wesley Liddick 2e61914c48 Merge pull request #3880 from Wei-Shaw/fix/compact-body-signal-sse-bridge
fix(compact): body-signal 客户端流式请求的响应合成回 SSE(修复 #3875)
2026-07-09 22:39:31 +08:00
shaw 92b283d9eb fix: 修复 SSE 桥接 appendEvent 中 errcheck 告警 2026-07-09 22:34:13 +08:00
shaw 1c2e6503c6 feat: 版本徽章新增近3个历史版本在线回退与手动回退指引
后端:
- UpdateService 新增 ListRollbackVersions/RollbackToVersion,回退目标强制
  限定为比当前版本更旧的近3个正式版本(排除当前/更新/预发布/草稿),
  越界返回 400 ROLLBACK_VERSION_NOT_ALLOWED;下载复用既有 HTTPS 域名
  白名单 + checksum 校验 + 原子换二进制管线
- GitHubReleaseClient 新增 FetchRecentReleases(releases 列表 API)
- 新增 GET /admin/system/rollback-versions;POST /admin/system/rollback
  支持可选 {"version"} body,无 body 保持原 .backup 本地回退行为不变
- 端点均在 /admin 组 adminAuth(IsAdmin+TokenVersion)保护内

前端:
- VersionBadge「已是最新版本」状态下新增版本回退面板:radio 卡片选择
  近3个版本,手动回退方式按部署形态 tab 切换(脚本部署 curl 命令 /
  Docker 镜像 tag 指引),支持一键复制;release 构建提供一键回退并
  复用重启流程;源码构建仅提示不支持在线回退
- 下拉根元素重置 whitespace-normal,修复 sidebar-brand 的
  white-space:nowrap 继承导致的长文本溢出裁切

测试:服务层过滤/排序/上限/非法目标拒绝、handler 双模式与鉴权错误映射、
GitHub client 列表拉取、前端 API 请求体行为共 16 个新增用例
2026-07-09 22:30:04 +08:00
shaw 16c0613b21 fix(compact): body-signal 客户端流式请求的响应合成回 SSE
v0.1.147 的 body-signal 提升(#3804)把 Codex remote compact v2 的流式
/responses 请求改写为上游 unary /responses/compact(JSON),但把 JSON
文档原样写回给了按 Responses SSE 协议消费的客户端。Codex 只从
response.output_item.done 收集 item 且必须收到 response.completed,
收到 JSON 后报 "stream disconnected before completion: stream closed
before response.completed" 无限重连,每次重连再白烧一次上游 compact
配额(#3875,v0.1.146 无提升逻辑故正常)。

修复保留提升的全部收益(requireCompact 调度过滤、compact 模型映射、
白名单归一化、上游 unary JSON),补上协议转换缺失的响应半程:

- handler 在 body-signal 提升时记录原始 body 的 stream:true 意图
  (MarkOpenAICompactClientStream);path-based 请求不标记,Codex v1
  unary 协议与链式 sub2api 的 JSON 写回行为保持不变。
- 四个非流式写回点(handleNonStreamingResponse / handleSSEToJSON /
  handleNonStreamingResponsePassthrough / handlePassthroughSSEToJSON)
  对已标记的 2xx JSON 响应经 writeOpenAICompactSSEBridge 合成最小
  Responses SSE:每个 output[] item 一条 response.output_item.done
  (原始字段逐字节保留),最后一条 response.completed 携带完整
  response 对象。
- 按 codex-rs 解析器硬约束兜底:先 json.Compact 防 pretty JSON 换行
  破坏 SSE 帧;response.id 缺失时注入 resp_*(必填 string);usage
  缺 input_tokens/output_tokens/total_tokens 整数字段时整体删除,
  避免整条 completed 事件解析失败。
- 非 2xx 一律保持 JSON 原样,Codex 依赖 HTTP 状态码走重试链路。

新增 9 个 service 测试 + 4 个 handler 测试覆盖合成形态、id/usage 兜底、
path-based 不受影响、主链路/透传链路/上游 SSE 提取再合成三条端到端。

Fixes #3875
Refs #3777
2026-07-09 21:40:51 +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
Wesley Liddick e2c731abe4 Merge pull request #3873 from Wei-Shaw/fix/post-merge-audit-followups
fix: 落实 #3867-#3870 合并审计的全部跟进项
2026-07-09 20:13:21 +08:00
shaw 7918b1a9c5 fix: 落实 #3867-#3870 合并审计的全部跟进项
透传规则(跟进 #3868/#3870,refs #3857):
- CC/Messages 4 条协议转换路径改用共享 helper,走语义状态推断 +
  body 归一化,使按错误码配置的透传规则也能命中(原先传 0 恒不命中)
- helper 增加 platform 参数:本服务同时承载 openai/grok 平台账号,
  规则须按 account.Platform 匹配,消除硬编码平台错配
- /v1/responses 两条路径命中透传规则时补记 ops 上游错误事件,
  对齐 CC/Messages 与 antigravity 先例,消除监控盲区

用户角色管理(跟进 #3869):
- 补齐 EN 语言包缺失的 admin.users.form.roleLabel
- 新增"最后一个管理员不可降级"守卫,覆盖跨管理员互降致零 admin 锁死
- 角色变更/创建管理员落审计日志(含操作者 actor_admin_id)
2026-07-09 20:06:09 +08:00
Wesley Liddick 10102807e2 Merge pull request #3869 from Birditch/feat/admin-user-role-and-token-ranking
feat(admin): 用户角色管理 + 用户 Token 排行
2026-07-09 19:50:01 +08:00
Wesley Liddick 751cf5eea3 Merge pull request #3870 from fengshao1227/fix/response-failed-passthrough-rules
fix(gateway): CC/Messages 路径 SSE response.failed 应用错误透传规则
2026-07-09 19:49:32 +08:00
Wesley Liddick a8505877ff Merge pull request #3868 from wucm667/fix/openai-sse-response-failed-error-passthrough
fix: OpenAI SSE response.failed 应用错误透传规则
2026-07-09 19:49:04 +08:00
Wesley Liddick f3380dbd62 Merge pull request #3867 from heathermhuang/codex/postmerge-grok-issues-3848-3861
fix: Grok OAuth, image, usage, and quota handling
2026-07-09 19:48:32 +08:00
shaw feef0bc0b1 chore: update sponsors 2026-07-09 19:08:00 +08:00
github-actions[bot] 0ee51b45f8 chore: sync VERSION to 0.1.147 [skip ci] 2026-07-09 10:10:28 +00:00
li 8f97953e51 fix(gateway): SSE response.failed 应用错误透传规则,不再硬编码 502
Fixes #3857
2026-07-09 18:09:37 +08:00
BirditchandClaude 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
BirditchandClaude Opus 4.8 64fdc11ec4 feat(admin): 用户创建/编辑支持选择与修改角色 (user/admin)
- 创建用户时可指定角色,缺省仍为 user,不再硬编码为普通用户
- 编辑用户时可在 user/admin 之间切换角色
- 后端对角色做 admin/user 合法性校验
- 防锁死保护:管理员不能把自己降级为普通用户(与既有"不能禁用/删除 admin"保护一致;降级其他管理员仍允许)
- 前端创建/编辑弹窗新增角色下拉,复用既有 i18n 文案
- 新增角色创建/更新/非法值/防降级单元测试

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 06:04:06 -04:00
wucm667 1da3501af5 fix: apply error passthrough to OpenAI response.failed streams 2026-07-09 17:59:38 +08:00
Heatherm Huang 1a0a6ea9a8 fix: stabilize Grok quota probe model 2026-07-09 17:58:31 +08:00
Heatherm Huang b480545c19 fix: improve Grok OAuth, image, and usage flows 2026-07-09 17:54:08 +08:00
Wesley Liddick ba1f130d28 Merge pull request #3864 from fengshao1227/fix/frontend-i18n-and-site-logo-sanitize
fix(frontend): 补齐 en 语言包缺失 key 并对 site_logo 统一应用 sanitizeUrl
v0.1.147
2026-07-09 17:35:00 +08:00