Commit Graph
4497 Commits
Author SHA1 Message Date
xlplboandClaude Fable 5 e2b68d1f90 fix(apicompat): tool_choice 仅转发实际存在于转换结果中的工具
此前只检查转换后是否还剩任意工具,不校验 tool_choice 指向的工具是否幸存:
强制选择被丢弃的服务端工具(如 web_search)或指向不存在名字时,选择项被
原样转发,chat 上游因 tool_choice 指向未声明工具而 400。改为具名选择项仅
在目标存在于转换后工具集时转发,服务端工具类选择项随工具本身丢弃;
"auto" 等字符串形式保持原样转发。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NWQyEgFKKbdve67G6qCoAU
2026-07-10 21:06:45 +08:00
xlplboandClaude Fable 5 a2cdaa6419 fix(apicompat): 内置 tool_search 与同名工具撞名时显式拒绝请求
tool_search 服务端工具降级后的代理 function 不能改名(codex 的模型侧按
tool_search 这个名字调用),与客户端声明的同名 function/custom 工具无法
区分:去程产生重复声明,回程会把普通工具的调用劫持还原成 tool_search_call。
与 namespace 摊平撞名的处理一致,在请求转换阶段显式报错(网关 400);
重复声明 type=tool_search 去重后只产出一个代理,不拒绝。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NWQyEgFKKbdve67G6qCoAU
2026-07-10 21:06:26 +08:00
xlplbo eb4d005031 Merge remote-tracking branch 'upstream/main' 2026-07-10 20:46:38 +08:00
Wesley Liddick deff3123de Merge pull request #3984 from Wei-Shaw/fix/issue-3901-codex-identity-pairing
fix(openai): originator 与最终 User-Agent 首段配套收口,修复 codex 上游 404(#3901)
v0.1.151
2026-07-10 19:36:46 +08:00
shaw 8a51119e39 fix(openai): pair originator with final User-Agent for codex upstream
上游 /backend-api/codex 的 404 gating 是配套校验:originator 必须与
User-Agent 首段(首个 '/' 前的 client 名)配套且为官方 codex 身份,
错配(如 originator=codex_cli_rs + UA=codex-tui/...)一律 404;version
头若携带须 >= 0.144.0。

修复:
- pkg/openai 新增 PairCodexClientIdentity:由最终出站 UA 推导配套
  originator(含 CODEX_INTERNAL_ORIGINATOR_OVERRIDE 尾部括号组身份恢复、
  精确集合大小写归一、长度/字符集校验)
- service 新增 enforceCodexIdentityHeaders 终态收口:originator 按最终
  UA 重配,推导不出官方身份整体回退默认 Codex CLI 身份;version 低于
  0.144.0 提升为内置版本;originator 缺失时 no-op(保护 messages bridge)
- 接入非透传/透传/WS 三条转发路径(透传与 WS 删除会把 codex-tui 等官方
  UA 强改为 codex_cli_rs 造成错配的旧兜底)、用量探针(指纹缓存 UA 与硬
  编码 originator 错配)、账号 responses/图像测试(opencode 错配)
- messages 兼容桥构建前显式打 bridge 标记,防止映射到非 gpt-5/codex
  模型时收口误改其刻意最小化的请求形态

Fixes #3901
2026-07-10 19:11:26 +08:00
xlplboandClaude Fable 5 f1082bb78f fix(apicompat): namespace 摊平名撞名时显式拒绝请求
摊平名与顶层 function/custom 工具撞名、或跨 namespace 摊平出同名时,
chat 上游无法按 namespace 区分调用归属:此前重复声明照发上游、回程
固定命中其中一条映射,调用可能被还原到错误工具。这类请求在原生
Responses 上游合法,歧义由摊平转换制造且不可消除,改为在请求转换
阶段直接报错(网关返回 400 invalid_request_error 并点名冲突双方);
同一 (namespace, 子工具) 的重复声明去重后不拒绝。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NWQyEgFKKbdve67G6qCoAU
2026-07-10 17:38:48 +08:00
xlplboandClaude Fable 5 7942338328 fix(apicompat): 回程还原 namespace 子工具调用,修复 Codex MCP 工具 unsupported call
Codex 0.14x 将 MCP 工具声明为 namespace 工具,chat 桥去程摊平为
"<namespace>__<name>" function 工具后,回程仅原样回传平铺名的
function_call 项;codex 按 namespace+name 路由查不到该名字,所有
MCP 工具调用被判为 unsupported call。

- NamespaceToolNames 构建摊平名 →(namespace, 子工具名)反查表
  (摊平名超长带截断哈希,无法按字符串切分还原)
- 非流式/流式回程命中映射时还原为裸子工具名 + namespace 字段,
  ResponsesOutput 新增 Namespace 字段并同步 wire 层白名单
- 回退桥入口将映射与 CustomTools/ToolSearchDeclared 一并穿入

已在测试机经 codex exec + MCP server 端到端验证。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NWQyEgFKKbdve67G6qCoAU
2026-07-10 17:38:17 +08:00
Wesley Liddick 5260a42a0b Merge pull request #3953 from lyon-le/feat/openai-fast-policy-user-scope
feat(openai): 支持用户级 Fast/Flex 策略
2026-07-10 17:31:55 +08:00
Wesley Liddick 815516d8d3 Merge pull request #3969 from jinfeijie/fix/grok-responses-reasoning-effort
fix(grok): preserve compatible reasoning effort
2026-07-10 17:31:41 +08:00
jinfeijie bot 5a0dd510e5 fix(grok): remove obsolete helper 2026-07-10 17:11:04 +08:00
jinfeijie bot 0fa1eb85ec fix(grok): preserve compatible reasoning effort 2026-07-10 16:58:17 +08:00
Wesley Liddick 6dd3274aaf Merge pull request #3948 from superman2003/fix/gpt56-billing-usage-integrity
fix(openai): correct GPT-5.6 billing and usage gaps
2026-07-10 15:45:18 +08:00
Wesley Liddick d0f6f27d5f Merge pull request #3941 from Tassoi/codex/fix-image-gen-namespace-strip
fix(image): strip Codex image_gen namespace declarations
2026-07-10 15:45:05 +08:00
Wesley Liddick 6a2063b374 Merge pull request #3883 from ShuminFu/fix/setup-token-auto-refresh
fix: 后台自动刷新纳入 setup-token 账号(修复 8h 后 401)
2026-07-10 15:44:54 +08:00
Lyonle f2966530c5 feat(openai): 支持用户级 Fast/Flex 策略 2026-07-10 15:16:09 +08:00
superman2003 de28eba3c8 fix(openai): harden GPT-5.6 billing and usage 2026-07-10 15:13:11 +08:00
Tassoi d3a1835ed7 fix(image): strip Codex image_gen namespace declarations 2026-07-10 06:37:06 +00:00
Shumin a495d5e302 test: 更新断言以覆盖 setup-token 纳入后台刷新
- ListOAuthRefreshCandidates SQL 断言由 type = 'oauth' 改为
  type IN ('oauth', 'setup-token')。
- ClaudeTokenRefresher.CanRefresh 增加 anthropic setup-token → true 用例。
2026-07-10 02:27:33 -04:00
github-actions[bot] 9a2f11b4e2 chore: sync VERSION to 0.1.150 [skip ci] 2026-07-10 06:27:11 +00: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 等后缀变体的识别。
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
xlplboandClaude Fable 5 18e26c127c Merge remote-tracking branch 'upstream/main'
解决 backend/internal/service/openai_gateway_responses_chat_fallback.go 冲突:
将本地 tool_search/custom 工具改动(customTools/toolSearch 穿参与流状态标记)
移植到上游重构后的 CC 公共管线;同步适配上游新增调用点
openai_gateway_messages_chat_fallback.go 的 ChatCompletionsResponseToResponses 签名。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F8zMzeFAumSddraEw1FUeG
2026-07-10 09:27:48 +08:00
benjamin 4a2b10c94e feat(openai): support GPT-5.6 cache write billing 2026-07-10 09:08:58 +08:00
Shumin 99da308196 fix: 后台自动刷新纳入 setup-token 账号
setup-token 的 access_token 同为 8h 短期令牌(expires_in=28800),
此前被后台刷新服务排除,到期后请求返回 401 authentication_error。
放开 CanRefresh 与候选查询的 type='oauth' 限制,与手动刷新入口
(account.IsOAuth()) 保持一致;实际刷新仍由 NeedsRefresh 基于
expires_at 门控并在分布式锁下执行,不会过度刷新。
2026-07-09 11:05:05 -04: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