Commit Graph
3616 Commits
Author SHA1 Message Date
Wesley Liddick d2f87c612e Merge pull request #6638 from feeeei/feat/images-url-to-b64json-backfill
feat(images): 账户开关将生图结果 url 下载回填为 b64_json
2026-09-05 16:24:40 +08:00
Wesley Liddick fb44e2dd09 Merge pull request #6514 from StarryKira/codex/anthropic-reasoning-pricing
feat: add Anthropic reasoning effort and Fable 5.1 max pricing
2026-09-05 16:19:18 +08:00
Wesley Liddick c42d78e26c Merge pull request #6571 from DuskLin/feat/codex-ultrafast-tier
feat(codex): support ultrafast service tier
2026-09-05 16:18:16 +08:00
Wesley Liddick 2dc287f2e0 Merge pull request #6636 from specialpointcentral/cyber-ws-recording-fix
fix(openai): record WS cyber policy failures across paths
2026-09-05 16:17:33 +08:00
Wesley Liddick 83094abf21 Merge pull request #6536 from wucm667/fix/issue-6526-mapped-model-scheduling
fix(openai): schedule accounts with mapped model
2026-09-05 16:17:04 +08:00
Wesley Liddick 0d9e7e1530 Merge pull request #6628 from baryon/contrib/openai-gpt6-astra-capability-sync
fix(openai): persist GPT-6 Astra Codex capabilities from upstream sync
2026-09-05 16:07:50 +08:00
Wesley Liddick 9b4fcfb897 Merge pull request #6606 from luckydududu/feat/claude-cli-version-env-override
feat(claude): allow operators to override the advertised CLI version
2026-09-05 16:05:33 +08:00
Wesley Liddick 9517f12cdd Merge pull request #6510 from wall-wxk/fix/release-session-slot-on-forward-failure
fix(gateway): 转发失败的请求立即释放会话槽,不再占用整个空闲超时窗口
2026-09-05 16:05:06 +08:00
Wesley Liddick 40f4d450be Merge pull request #6507 from wucm667/fix/issue-6501-glm53-thinking-effort
fix(gateway): normalize GLM-5.3 thinking effort
2026-09-05 16:04:16 +08:00
Wesley Liddick 620eb3fd00 Merge pull request #6581 from r266-tech/r266/forward-opencode-session
fix(openai): scope OpenCode session forwarding
2026-09-05 16:03:57 +08:00
Wesley Liddick 7b271bbee9 Merge pull request #6529 from wucm667/fix/issue-6521-preserve-passthrough-reasoning
fix(openai): preserve reasoning effort in API-key passthrough
2026-09-05 16:02:56 +08:00
feeeei c227863d51 fix(images): 生图 url 回填下载拒绝私网目的地并只信字节嗅探
账户开关 images_url_to_b64_json 下载的图片 url 来自上游响应,是不可信输入。此前沿用
base_url 的 security.url_allowlist 策略,默认配置下只做格式校验,上游返回
localhost:8080 之类地址时网关会真的去请求内网。

- 下载 URL 主机为 localhost、回环、私网、链路本地、未指定地址的字面量时直接拒绝,
  不受 security.url_allowlist 配置影响(urlvalidator 导出 IsBlockedHost)
- 新增 ctx 标记 WithHTTPUpstreamPublicHostsOnly:共享上游客户端对带标记的请求无视配置
  校验解析后 IP,并为其克隆客户端挂 redirectChecker,重定向保持跟随但每一跳都校验
- 下载内容改为只信 http.DetectContentType 嗅探结果且限 png/jpeg/webp/gif,
  响应头不再作为依据
- 下载失败仍只记日志并保留原样;超时与端口策略不变
2026-09-05 15:50:56 +08:00
Qi HU 2da31290a1 fix(openai): record WS cyber policy failures across paths
Cyber-policy detection only inspected response.failed, and the ingress check ran after error-specific early returns. As a result, error-shaped failures and the connection-pool, HTTP-bridge, and WSv2 paths could miss cyber-policy hits.

Centralize event marking and invoke it before retry and failover returns across the WebSocket implementations. Preserve the recorded guard during account failover and defer connection blocking until the logical failover chain completes, avoiding duplicate records while ensuring subsequent turns are blocked.
2026-09-05 15:32:29 +08:00
feeeei 3c53ba01a7 feat(images): 账户开关将生图结果 url 下载回填为 b64_json
部分第三方 GPT-image 上游把 Images 响应里的 b64_json 换成 url,按官方接口实现的
客户端读不到图。账户 extra.images_url_to_b64_json 开启后,OpenAI API Key 的
Images 非流式响应里 b64_json 缺失或为空且 url 非空的项,由网关下载 url 内容并以
base64 回填 b64_json,url 与其余字段原样保留;异步生图任务复用同一路径。

- 下载经账户代理发起,沿用 base_url 的出站 URL 校验策略(validateUpstreamBaseURL
  抽出 validateOutboundURL,nil cfg 按仅格式校验处理),单图上限 20MB 且须为图片
  内容(响应头或字节嗅探);data: URL 直接取 base64 载荷
- 单项下载失败仅记日志并保留原样;客户端显式 response_format=url 时不回填;
  流式响应不处理
- 创建/编辑账户弹窗在 OpenAI API Key 的 Responses 模式块后新增“生图结果 URL 转
  base64”开关,中英文案;新增 openai_images_b64_backfill_test.go
- 只被 unit 标签测试引用的定价目录测试辅助补上 //go:build unit(admin 包整文件加标签,
  service 包的 newPricingServiceFromModelPricing 搬到 pricing_stub_helpers_unit_test.go),
  消除 golangci-lint 在默认标签下的 unused 报错
2026-09-05 15:17:57 +08:00
Wesley Liddick 07bf8b92fd Merge pull request #6550 from weiness/fix/alipay-payment-reconciliation
修复支付宝回调延迟或丢失,已支付订单可能长时间停留在待支付状态的问题
2026-09-05 15:08:56 +08:00
Wesley Liddick 63dc24b5e8 Merge pull request #6626 from wucm667/feat/issue-6624-none-reasoning-mapping
feat(openai): allow none as reasoning mapping source
2026-09-05 15:06:32 +08:00
Wesley Liddick 8f1d6af3ed Merge pull request #6531 from wucm667/fix/issue-6524-continuation-unavailable-recovery
fix(openai): recover unavailable continuation responses
2026-09-05 15:06:02 +08:00
Wesley Liddick 85f431a072 Merge pull request #6620 from wucm667/fix/issue-6615-astra-messages-cache
fix(openai): enable Astra messages prompt caching
2026-09-05 15:04:13 +08:00
Wesley Liddick eba6ea5639 Merge pull request #6590 from wucm667/fix/issue-6582-search-tool-capability
fix(codex): advertise search capability for bridged routes
2026-09-05 15:03:31 +08:00
Wesley Liddick c4e6dcfd80 Merge pull request #6602 from ZeroClover/feat/codex-manifest-pinned-accounts
feat(codex): pinned-accounts Codex model manifest for OpenAI groups
2026-09-05 14:51:17 +08:00
Wesley Liddick 701f844755 Merge pull request #6555 from feeeei/feat/usage-upstream-request-id
feat(usage): 用量记录落库直接上游的请求 ID,并支持按账户配置响应头名
2026-09-05 14:36:07 +08:00
Wesley Liddick 91cf660377 Merge pull request #6397 from feeeei/fix/openai-ws-replay-oom-6382
fix(openai-ws): eliminate O(T²) replay copying and invalid_encrypted_content retry storms
2026-09-05 14:32:11 +08:00
Wesley Liddick 78e1aaedb9 Merge pull request #6535 from feeeei/feat/pricing-custom-file-hot-reload
feat(pricing): fallback/override 定价文件按内容哈希热重载,改动无需重启生效
2026-09-05 14:31:09 +08:00
shaw 708b85a6a4 fix: complete upstream request id handling 2026-09-05 14:18:13 +08:00
shaw 1cab4d8c22 fix: make custom pricing reload coherent 2026-09-05 14:18:13 +08:00
Wesley Liddick d8b9a83f8c Merge pull request #6492 from feeeei/main
fix(gateway): 负载感知调度补齐渠道模型限制的逐账号检查
2026-09-05 14:06:21 +08:00
Long LiandCursor a016bd4ba5 style: gofmt upstream models capability sync tests
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 14:58:51 +09:00
Long LiandCursor 983a3db3af fix(openai): persist GPT-6 Astra Codex capabilities from upstream sync
Official OpenAI hosts and models.dev entries without an api field left
Astra falling back to reasoning effort none and empty Fast tiers. Persist
complete per-model metadata, advertise Astra reasoning/Fast locally, and
surface partial sync warnings when image models remain incomplete.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 14:45:06 +09:00
wucm667 7969751f1f feat(openai): allow none as reasoning mapping source 2026-09-05 12:32:30 +08:00
wucm667 4aaf5cb73b fix(openai): enable Astra messages prompt caching 2026-09-05 10:58:05 +08:00
LuckyandClaude Opus 5 e9bad40b10 feat(claude): allow operators to override the advertised CLI version
Anthropic gates newer models on a minimum Claude Code client version. With
CLICurrentVersion pinned at 2.1.220, claude-fable-5-1 fails every request with
"Claude Code 2.1.220 does not support this model; version 2.1.251 or newer is
required", and the only fix is a release that bumps one constant.

Add SUB2API_CLAUDE_CLI_VERSION, mirroring what internal/pkg/xai already does
with XAI_GROK_CLI_VERSION. CLICurrentVersion remains the built-in pin; the new
CLIVersion() is what every consumer reads. With no env var set the resolved
value equals the pin, so existing deployments are unaffected.

The value is resolved once at package init rather than per call: the User-Agent
header and the request body's cc_version are written by different code paths for
the same request, and reading different values would make that request
contradict itself.

Validation is strict (three numeric segments, not below the pin) because
identity_service.go documents what a malformed version does once it reaches an
account's persistent fingerprint: sustained 429s without reset headers, 5s
fallback cooldown, pool collapse into a 503 storm, and no reset entry point.
Invalid values warn and fall back rather than being silently dropped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168uDMAj9anaJrnH8CeFze6
2026-09-04 18:01:34 +00:00
Zero Clover 1e28ef5942 feat(codex): pinned-accounts Codex model manifest for OpenAI groups 2026-09-05 00:10:24 +08:00
wucm667 c7538cd256 fix(codex): advertise search capability for bridged routes 2026-09-04 16:43:15 +08:00
r266-tech 6cf645f87c fix(openai): scope OpenCode session forwarding 2026-09-04 12:45:06 +08:00
刘佳林 126ac24c8c feat(codex): support ultrafast service tier
Accept service_tier=ultrafast on the OpenAI/Codex gateway, advertise it
on GPT-5.6 Sol in the Codex model catalog, and include it in ChatGPT
OAuth routing hints so Codex clients can select Ultrafast.
2026-09-04 10:14:29 +08:00
wucm667 f5ae32e53f fix(gateway): normalize GLM-5.3 thinking effort 2026-09-04 08:15:41 +08:00
feeeei de27905e88 feat(usage): 用量记录落库上游请求标识并支持按账户配置响应头名
- usage_logs 新增 upstream_request_id 列(迁移 232)与仅索引非空行的 CONCURRENTLY 部分索引(迁移 233,runner 登记失效索引清理)
- 账户 extra.upstream_request_id_header 指定要读取的上游响应头,只读该头;留空不记录;创建/更新/批量入口校验头名合法且不超过 64 字节
- ForwardResult/OpenAIForwardResult 携带 UpstreamHeaders,中央计费按账户解析落库,WS 轮次保持 NULL
- 管理端用量明细新增默认隐藏的"上游ID"列,带与请求ID列一致的复制按钮,并同步导出
- 创建/编辑账户弹窗新增"上游ID"输入(UpstreamRequestIdHeaderField),提示按接入类型与平台分条列出常见头名
- HelpTooltip 悬停模式下指针移入提示框时保持打开,便于选中复制提示内容
2026-09-03 18:02:15 +08:00
weiness de8d756afa fix(payment): reconcile pending Alipay orders 2026-09-03 16:33:30 +08:00
Wei-Shaw abc07bb079 test(ops): satisfy errcheck and gofmt in proxy attribution tests 2026-09-03 15:23:22 +08:00
wucm667 78fc7b171e test: skip live token comparison on network errors 2026-09-03 15:16:18 +08:00
Wei-Shaw 4c1f920d58 fix(ops): close proxy attribution gaps and bound queued upstream events
Follow-up to the event-time proxy snapshot: every upstream attempt now
carries attribution, the direct/unknown contract is enforced everywhere,
and the queued upstream_errors array has hard bounds again.

Attribution coverage
- compact fallback retry helper and the streaming compact failover event
  now stamp proxy_id/proxy_name; the non-streaming SSE compact retry
  previously dropped its first attempt on `continue` and now records it
- raw chat-completions stream truncation events (new on main) attributed
- Anthropic/Bedrock transport errors get attribution inside the shared
  handleUpstreamTransportError helper, so all five callers inherit it
- OpenAI first-output timeout takes attribution from the caller: HTTP
  callers pass the HTTP rule, the WS passthrough relay passes the WS rule
  (no managed proxy => unknown, never direct, because http.DefaultClient
  may honor environment proxies)

Contract hardening
- single opsUpstreamProxyAttribution returns (id, name) from one decision;
  a hydrated Proxy without a durable ID is unknown, not id=null+name
- both normalizers (struct at append time, JSON on detail reads) enforce
  proxy_id==null <=> sentinel name; blank managed name => "proxy"
- detail-read normalization edits only the attribution keys via sjson, so
  keys from older struct versions and stored key order are preserved

Queue bounds
- keep at most 256 attempts and ~512 KiB serialized per entry, newest
  first; the oldest retained event records dropped_earlier_attempts
- attempts outside the 16-event body window trim url/message to 512 bytes
- restore the empty-event drop rule, judged before the body window clears
  detail so older real attempts survive

Tests cover each site above (managed proxy, direct, WS unknown), the
normalizer invariants, key/order preservation, and the count/byte bounds.
2026-09-03 15:11:36 +08:00
wwcchh0123 e9e3c46cb7 fix(ops): snapshot proxy on upstream errors 2026-09-03 14:20:39 +08:00
feeeei fdc2ec17e6 feat(pricing): fallback/override 定价文件按内容哈希随定时器热重载
PricingService 的定时器(hash_check_interval_minutes,默认 10 分钟)每轮先做
远程目录哈希同步,再比对 fallback_file/override_file 两个文件内容的联合 sha256
(customFilesHash),变化时从本地 model_pricing.json 重建叠加层,只替换内存数据
与指纹,不改远程同步锚点 localHash。只配置了自定义文件而 remote_url 为空时
调度器同样启动。

- 三条重建路径(启动加载、远程下载、热重载)统一走 buildPricingData,指纹在合并
  读取之前采样,并发改文件只会落后于数据、下一轮补重建
- 删除文件视为该层清空,下一轮生效;文件存在但不可读或不是 JSON 对象时保留旧数据、
  不更新指纹,每轮重试并告警
- config.example.yaml 同步生效说明;新增 pricing_service_hot_reload_test.go
2026-09-03 10:35:20 +08:00
wucm667 b6740c937f fix(openai): recover unavailable continuation responses 2026-09-03 10:26:12 +08:00
wucm667 10c8f523c4 fix(openai): preserve passthrough reasoning effort 2026-09-03 09:42:50 +08:00
haruka 8249ab37db feat: add Anthropic reasoning effort pricing controls 2026-09-02 20:16:57 +08:00
wall-wxkandClaude Opus 4.6 9be9c0b68c fix(gateway): 转发失败的请求立即释放会话槽,不再占用整个空闲超时窗口
会话数量限制(max_sessions)此前只有空闲超时自动过期,没有任何主动释放
机制:请求在选号阶段注册会话后,即使转发失败(上游错误/客户端断开/换号
耗尽),该 session hash 也会占住槽位直到空闲超时(默认 5 分钟),导致
max_sessions 受限的账号在窗口内拒绝所有新会话。

修复:
- SessionLimitCache 新增 UnregisterSession(Redis ZREM),立即移除会话注册
- GatewayService 新增 ReleaseAccountSession,适用条件与 checkAndRegisterSession 对齐
- Messages 主路径:记录 failover 链上注册过会话槽的账号,请求最终失败时
  统一释放;failover continue / profit veto / 兜底分组切换时按次即时释放;
  成功及"上游已计量部分结果"(#5148)保持既有空闲超时语义
- CountTokens:转发失败时同样释放选号时注册的会话槽

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-02 18:45:20 +08:00
feeeei 9ad3865690 fix(gateway): 负载感知调度补齐渠道模型限制的逐账号检查
渠道 billing_model_source=upstream 时,限制模型只能按账号映射后的上游模型
逐账号判定。GatewayService.SelectAccountWithLoadAwareness 的负载感知各层
(模型路由候选、路由内粘性 gate、无路由粘性 gate、负载感知候选及其兜底)
此前都没有这一判定,load_batch_enabled 默认开启,anthropic/gemini/antigravity
分组的渠道白名单实际不生效。

现在入口算一次 needsUpstreamChannelRestrictionCheck,各层共用同一判定;
候选因渠道限制筛空时记 warn 并返回带 channel pricing restriction 的
ErrNoAvailableAccounts,与预检路径一致。
2026-09-02 11:46:37 +08:00
刘佳林 77729e2723 merge: resolve conflicts with upstream/main
Keep model-scoped reasoning effort mappings together with the
deny-or-downgrade ceiling control that landed on main.
2026-09-02 10:01:42 +08:00
Wesley Liddick 6566039bc8 Merge pull request #6470 from aofee/codex/fix-ws-passthrough-missing-terminal
fix(openai-ws): reject passthrough close before terminal event
2026-09-02 09:42:13 +08:00