dailingfei
8ce7b9a8f6
feat: configure Claude OAuth system prompt blocks
2026-06-13 04:12:13 +08:00
bwlc and Claude Fable 5
c70c6a2659
feat(渠道监控): 检测间隔支持正负随机抖动配置
...
新增 jitter_seconds 配置:每轮调度在 interval 基础上 ± [0, jitter]
均匀随机偏移触发,避免多个监控以固定节奏同步请求上游。
- ent schema 新增 jitter_seconds 字段(默认 0),附迁移 151
- 校验:jitter >= 0 且 interval - jitter >= 15s(创建/更新均校验)
- runner 由固定 ticker 改为每轮重新随机化的 timer,0 抖动时行为不变
- 前端监控表单新增「随机抖动 (± 秒)」输入框,上限随间隔联动
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-06-12 22:09:53 +08:00
wucm667
c1c28ac7bb
fix(gateway): 解压 zstd 上游响应体
2026-06-12 15:06:01 +08:00
wucm667
edfd5e3736
fix(apicompat): default tool strict to false
2026-06-12 15:01:58 +08:00
wangziwenunique
f6e0ebc6bf
fix: preserve Anthropic window cooldowns
2026-06-12 13:35:03 +08:00
DaydreamCoding and Claude Opus 4.8
b62b573f7f
feat(openai): cyber_policy 硬阻断全链路透传、审计与计费
...
上游对单次请求下发 error.code=cyber_policy 硬阻断时,网关在所有端点
(/v1/responses、/v1/chat/completions、/v1/messages、WebSocket)及流式/
非流式路径下,将该结果原样透传给客户端,绝不 failover、换号或同步拦截;
命中后异步完成审计与计费:
- 风控中心记录 cyber_policy 留痕并发送通知邮件,落库先于发信,SMTP 阻塞
不影响留痕
- ops 错误请求记录,状态码对齐客户端实际接收(流式 200 / 非流式 400)
- 用量明细标记 request_type=cyber,按上游真实 token 计费,HTTP 与
WebSocket 计费口径统一,零 token 命中不误扣
- 会话级自动屏蔽(管理员开关,默认关):命中的会话在可配 TTL 内本地拦截
不再发往上游,仅屏蔽该会话不影响同 Key 其他会话
- 封号计数排除开关:可选让 cyber 命中不计入自动封号,命中当次不判定且
历史行在违规计数中一并排除
WebSocket 多轮连接下 cyber 标记按 turn 生命周期管理,逐轮独立检测与记录;
透传的错误响应不被兜底逻辑追加内容污染。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-12 01:47:01 +08:00
jjaw
e4c255a77a
fix:account expiry autopause index
2026-06-12 01:38:09 +08:00
feitianbubu
b256f91141
fix(gateway): intercept max_tokens=1 haiku probes for streaming requests too
2026-06-11 20:46:47 +08:00
wucm667
f8c80bf038
fix(auth): apply promo codes to oauth signups
2026-06-11 18:55:27 +08:00
wucm667
65559ac589
fix(antigravity): merge system role messages
2026-06-11 18:37:00 +08:00
方程 and Claude Opus 4.7
6bf6722bae
chore: gofmt test file
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-11 17:45:09 +08:00
方程 and Claude Opus 4.7
0da1fe28ef
fix(openai): prevent false image billing on text-only /v1/responses requests
...
Two defects in the image output counter could inflate imageCount for
text-only responses, causing per-image charges instead of token billing:
1. addDataArray counted every element in a top-level "data" array
without checking whether each element contained actual image output
(url/b64_json). Non-image objects in a "data" array are now skipped.
2. addImageOutputItem accepted image_generation.completed items with
no result/b64_json/url, inflating the count. These items are now
filtered the same way as every other item type.
Fixes #3196
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-11 16:56:43 +08:00
jjaw
727ac3f689
fix: add app_session_terminated to non-retryable refresh errors / 将 app_session_terminated 添加到不可重试的刷新错误中
2026-06-10 22:32:04 +08:00
jjaw
fa8f1749f5
fix: treat invalid_refresh_token as non-retryable / 将 invalid_refresh_token 判定为不可重试
2026-06-10 14:21:44 +08:00
shaw
0acf00c4a1
Add admin compliance acknowledgement gate
2026-06-10 14:16:51 +08:00
Wesley Liddick
c32e29bab0
Merge pull request #3187 from jianjianai/fix/gateway-debug-log-loop
...
优化调度日志循环开销 / Reduce debug logging overhead in scheduler hot path
2026-06-10 09:58:40 +08:00
Wesley Liddick
0c997d41a9
Merge pull request #3176 from jianjianai/fix/precompute-model-body-replacement
...
优化 OpenAI 网关 failover 流程,避免账号切换时重复对请求体执行 JSON model 替换。
2026-06-10 09:58:19 +08:00
Wesley Liddick
f0748b98f6
Merge pull request #3173 from jianjianai/fix/idempotency-utf8-truncation
...
fix idempotency response utf8 truncation / 响应缓存按字节截断时可能切断 UTF-8 多字节字符的问题。
2026-06-10 09:58:09 +08:00
Wesley Liddick
dd709f5985
Merge pull request #3181 from codeQuest-fly/fix/gateway-upstream-error-double-write
...
fix: avoid double-writing error frame on non-stream upstream errors
2026-06-10 09:26:18 +08:00
Wesley Liddick
5cb17fdc4f
Merge pull request #3184 from touwaeriol/fix/bedrock-beta-and-error-passthrough
...
fix(gateway): prevent error passthrough double-write and Bedrock beta token leakage
2026-06-10 09:00:21 +08:00
shaw
d662c97302
feat: claude-fable-5
2026-06-10 08:58:06 +08:00
jjaw
2c27548b82
优化调度日志循环开销
2026-06-10 01:03:01 +08:00
erio
448936d965
fix(ci): fix gofmt, errcheck, and test for supported context-management beta token
2026-06-10 00:46:19 +08:00
erio
12962bab24
refactor(bedrock): merge header filtering into ApplyBedrockCCCompat
...
Move anthropic-beta header filtering from separate FilterBedrockBetaHeader
into ApplyBedrockCCCompat, so one function handles all CC compat processing
(body cleanup + header filtering). Change signature from ctx to *gin.Context
to access request headers. Remove the redundant separate call in handler.
2026-06-10 00:18:09 +08:00
erio
bf28a0098a
fix(bedrock): filter unsupported top-level fields and fix beta token cleanup
...
- Remove `provider` and `metadata` fields from Bedrock request body.
Bedrock returns 400 ValidationException for unknown top-level fields.
- When filtered beta tokens list is empty, delete any pre-existing
`anthropic_beta` field in body to prevent client-injected tokens
from leaking to Bedrock unfiltered.
- Add `context-management-2025-06-27` and `fine-grained-tool-streaming-2025-05-14`
to bedrockSupportedBetaTokens whitelist per AWS documentation.
2026-06-10 00:16:30 +08:00
erio
20f3f2049b
fix(gateway): complete MarkResponseCommitted coverage for all platforms
...
Add MarkResponseCommitted to 7 error-writing helper functions and
4 early-return branches in OpenAI handlers, plus 3 inline c.Data paths.
Helper functions (1 line each, covers 60+ call sites):
- writeGatewayCCError, writeResponsesError (Anthropic compat)
- writeClaudeError, writeGoogleError (Gemini + Antigravity)
- writeChatCompletionsError (Gemini Chat Completions compat)
OpenAI handleErrorResponse/handleCompatErrorResponse:
- passthrough rule and ShouldHandleErrorCode branches return before
the existing MarkResponseCommitted, now each has its own Mark.
Inline c.Data: Gemini ForwardNative (2) + Antigravity ForwardGemini (1).
2026-06-10 00:16:08 +08:00
erio
6c88631690
fix(gateway): prevent double-write on error passthrough responses
...
Service layer writes a complete JSON error response then returns error.
Handler's ensureForwardErrorResponse couldn't distinguish this from
"no response written" and appended an SSE event, corrupting the body.
Use gin.Context flag: service marks MarkResponseCommitted(c) after
writing, ensureForwardErrorResponse checks IsResponseCommitted(c)
and skips. Zero function signature changes, zero error wrapping.
2026-06-10 00:15:51 +08:00
dailingfei
914c059f4a
fix: avoid double-writing error frame on non-stream upstream errors
...
When a Forward implementation already wrote a complete non-SSE (JSON) error
response to the client and returned an error -- e.g. the case-400 passthrough
in GatewayService.handleErrorResponse -- the handler unconditionally called
ensureForwardErrorResponse, which detected the writer was already written and
appended a fallback `data: {"type":"error",...}` SSE frame. The client then
received a corrupted body: the upstream JSON immediately followed by a stray
`data:` line.
Add gatewayForwardErrorAlreadyCommunicated (and the OpenAI counterpart) to
detect this case -- writer size changed AND Content-Type is not
text/event-stream -- and skip the fallback. SSE streams that only flushed
keepalive pings or partial data still receive a protocol-compliant terminal
frame, so strict SDKs (Codex CLI) do not see a silent EOF.
Applied consistently across the Messages / ChatCompletions / Responses
gateway handlers and the OpenAI chat/images handlers. Added regression tests
covering JSON passthrough, mid-stream SSE 400, nil-error and no-write cases.
2026-06-09 22:46:06 +08:00
jjaw
46bd7968a3
fix: reuse OpenAI failover error body
2026-06-09 21:56:35 +08:00
jjaw
2c45f91d3c
fix openai failover model body replacement
2026-06-09 21:52:04 +08:00
jjaw
c10598dfe5
fix idempotency response utf8 truncation
2026-06-09 20:08:20 +08:00
wucm667
da30c59923
fix(openai): fail over image server errors
2026-06-09 13:57:45 +08:00
wucm667
a67b10f468
fix(gateway): anchor responses fallback to input
2026-06-09 13:53:19 +08:00
DaydreamCoding and Claude Opus 4.8
329414ea4f
feat(admin): /admin/users 新增按用户 API Key 所在分组过滤
...
- 支持专用/公开/订阅/已禁用四类分组:按 api_keys.group_id 精确匹配,
排除软删除 key(EXISTS + DeletedAtIsNil);已禁用分组单独成区,
覆盖 key 仍挂在禁用分组上的用户
- 后端:UserListFilters.APIKeyGroupID;handler 解析 api_key_group_id;
repo HasAPIKeysWith 谓词;GetAllGroupsIncludingInactive 新接口
(/admin/groups/all?include_inactive=true)
- 前端:下拉按类型分区单选;UsersView 独立 allGroupsForApiKeyFilter
loader;分区标题用负数哨兵值修复 Vue :key 重复问题
- 测试:repo 集成 5/5(含软删除排除、多 key 去重、叠加 status 过滤)、
handler 单测 5/5、前端 vitest 6/6
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-08 22:54:01 +08:00
Jiahao Luo
d251487da8
fix(openai): propagate prompt cache key for chat completions
2026-06-08 11:13:18 +08:00
Wesley Liddick
8c782bcc81
Merge pull request #3083 from xzz0081/fix/non-streaming-content-type
...
fix: force Content-Type to application/json on non-streaming responses
2026-06-08 09:20:17 +08:00
Wesley Liddick
870cefddf5
Merge pull request #3097 from NeckBozia/fix/5h-resets-at-stale
...
fix(usage): sync 5h ResetsAt to SessionWindowEnd and zero expired window
2026-06-08 09:08:23 +08:00
Wesley Liddick
a2bf6ad77a
Merge pull request #3107 from DaydreamCoding/feat/proxy-failover-resilience
...
feat: 代理生命周期与故障健壮性增强
2026-06-08 08:59:15 +08:00
Wesley Liddick
d7eef1e942
Merge pull request #3104 from CoolCoolTomato/fix/api-key-exclusive-group-auth
...
fix(bug): Fix the bug related to unauthorized use of groups
2026-06-08 08:58:44 +08:00
Wesley Liddick
7b394ed157
Merge pull request #3094 from okbexx/fix-openai-sticky-group-validation
...
fix: ignore stale OpenAI sticky sessions outside request group
2026-06-08 08:49:09 +08:00
DaydreamCoding
af19d44327
feat(proxies): 代理有效期与失败回退
...
- schema/迁移: 代理有效期、提醒天数、失败回退配置 + 账号 fallback 来源字段
- service/repo/DTO/handler: CRUD 透传新字段 + 校验
- fallback 目标解析纯函数(链式解析 + 环检测 + 兜底)
- SweepExpiredProxies 到期改投账号 + outbox 失效
- ProxyExpiryService 后台到期扫描任务 + wire 注册
- 账号侧手动回切原代理 + fallback 来源徽章/按钮
- 前端: 创建/编辑表单、列表到期徽章、类型/API/i18n
- ops 告警: proxy_expired_count / proxy_expiring_soon_count 指标
- 导入导出携带有效期/回退字段(备用按 name 映射)
- 补全测试 stub + 集成测试 + review 问题修复
2026-06-08 00:01:30 +08:00
DaydreamCoding and Claude Opus 4.8
f20e6bf769
feat(ops): 新增 account_temp_unscheduled_count 告警指标
...
临时摘除(temp-unschedulable)的账号被 account_error_count 指标显式排除
(acc.HasError && TempUnschedulableUntil == nil),且 SetTempUnschedulable 不
改账号 Status,导致代理/凭据故障触发的自动摘除无法被现有告警覆盖。
新增 account_temp_unscheduled_count 指标,统计当前处于临时不可调度窗口
(TempUnschedulableUntil 未过期) 的账号数,打通对自动摘除的定向告警:
- evaluator computeRuleMetric 新增分支 + handler 允许列表;
- 前端联合类型、告警规则下拉项与 en/zh 文案同步。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-07 22:31:45 +08:00
DaydreamCoding and Claude Opus 4.8
217f85999c
fix(openai): /responses 传输层错误转 failover + 持久故障临时摘除账号
...
代理/网络等传输层失败(Do/DoWithTLS 返回 error、无 HTTP 状态码,例如 SOCKS5
代理凭据过期返回 "username/password authentication failed")此前直接写
502 "Upstream request failed" 并返回普通 error:既不 failover 到健康账号,
也不摘除故障账号,导致同一坏账号被反复调度、大量用户持续收到 502。
- 新增 classifyOpenAITransportError:typed-error 优先
(ECONNREFUSED/EHOSTUNREACH/ENETUNREACH、*net.DNSError.IsNotFound)
+ 字符串兜底(SOCKS5 认证失败无 typed 形式)区分持久 vs 瞬时。
- 新增 handleOpenAIUpstreamTransportError:记录 ops 错误;对持久故障调用
SetTempUnschedulable(10min,DB) + 内存 BlockAccountScheduling 摘除账号并打
稳定 WARN 事件;统一返回 *UpstreamFailoverError 让 handler 切换到健康账号;
context.Canceled(客户端断开)不 failover、不摘除。
- /responses 主路径、passthrough、chat-completions 回退三处统一接入共享 helper。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-07 22:31:45 +08:00
Wesley Liddick
d01e4fd84d
Merge pull request #3075 from bwliangc/feat/openai-cross-group-prev-response
...
fix(openai): 切组后剥离失配的 previous_response_id,修复跨组会话鉴权失败
2026-06-07 22:21:24 +08:00
CoolCoolTomato
1a86c6ce12
fix: enforce exclusive group access for api keys
2026-06-07 20:46:03 +08:00
bwlc and Claude Opus 4.8
9a0e439803
fix(openai): 跨组会话失配保护移到生效的 WSv2 路径并补测
...
87dd5f5d 把 previous_response_id 剥离保护加在了 HTTP Responses 路径,但该路径
在 previousResponseID != "" 时已无条件返回 400(0fcddce6 引入),剥离块恒不可达,
RemovePreviousResponseIDFromBody 也只被这段死分支调用、无覆盖。
- 删除 HTTP Responses 路径的死代码剥离块,留注释指明保护应在 WSv2 路径。
- 在 ResponsesWebSocket 首包(wsFirstMessage)处补回等价保护:previous_response_id
未命中当前分组粘连账号(StickyPreviousHit=false)时剥离,改用首包 input 重建;
带 function_call_output 的工具续链保持原样。这是 previous_response_id 真正生效、
会触发跨组会话链鉴权失败的路径。
- 为 RemovePreviousResponseIDFromBody 增加单元测试(现已有真实 caller)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-07 20:30:56 +08:00
NeckBozia
16bc876935
fix(usage): sync 5h ResetsAt to SessionWindowEnd and zero expired window
...
active poll 拿到新 5h ResetsAt 时只回写了 Extra.session_window_utilization,
没回写 SessionWindowEnd column;estimateSetupTokenUsage 读这个 column 作为 5h
窗口结束时间,导致被动采样模式下 dashboard 显示 utilization > 0 但 reset
时间渲染为「现在」。
- syncActiveToPassive 增加 UpdateSessionWindowEnd 回写
- estimateSetupTokenUsage 抄齐 Codex 分支的过期归零 guard,避免 active
poll 没回写时 UI 渲染矛盾
- UsageProgressBar 区分「待刷新」/「现在」语义;i18n key 中英补齐
2026-06-07 15:23:45 +08:00
okbexx
a436296357
fix: validate OpenAI sticky session groups
2026-06-07 14:15:27 +08:00
xzz0081
154e0ed6c5
fix: force Content-Type to application/json on non-streaming responses
...
When the gateway forces streaming to the upstream, the upstream returns
Content-Type: text/event-stream. In the non-streaming branches, the body
is correctly aggregated into JSON, but WriteFilteredHeaders has already
passed the upstream's text/event-stream header through. Since Gin's
c.JSON/c.Data only set Content-Type via writeContentType when it is not
already present, the SSE header is never overwritten -- so the body is JSON
while the header says SSE.
Downstream middlewares that decide "is this streaming?" by Content-Type
(e.g. new-api) then mis-handle the response as SSE, breaking non-streaming
JSON clients.
Fix: explicitly Set Content-Type to application/json right after
WriteFilteredHeaders in the three non-streaming JSON write paths.
2026-06-07 02:56:26 +08:00
feitianbubu
7386f38cf5
test(usage): API契约测试补充缓存创建/命中token字段
2026-06-06 22:43:06 +08:00