shaw
a6c80e8aa8
docs(audit): PR #3242 终审三路审计总报告——零 P0/P1
...
①整 PR 生产 diff 对抗审查(跨阶段交互)P0/P1/P2=0/0/0
②-race 全扫+count=3 抖动+integration 实测+embed 构建:零竞争零 flake
③59 文件全归类 A/B/C 零例外,'默认配置零行为变更'逐条核证成立
六轮审计累计:突变 13/13 捕获、热路径 allocs 全程恒等
2026-06-12 11:14:00 +08:00
shaw
8aef24f3a6
test(plugin): 修复默认注册表委托测试对 -count>1 的不幂等
...
终审第二路审计发现:该测试向进程级全局默认注册表注册探针且无法清理,
go test -count=2 同进程重跑撞重复注册 panic。改为已注册即复用探针,
使 -count>1 抖动扫描(审计常用手段)可覆盖本包。count=3 与 -race -count=2 验证通过。
2026-06-12 11:12:32 +08:00
shaw
1922c271c8
docs(phase-4): R6 勘误——AccountRuntimeBlocker'归属错误'债务经实施前核实撤回
...
代码事实:接口本就定义在消费者侧 ratelimit_service.go:37(评审称'定义在
openai 卫星文件'有误)、命名平台中立;实现挂 OpenAIGatewayService 正确
(守护 openai 调度器内部状态,非 openai 账号为设计内 no-op)。
执行 R6 重构=纯 churn,撤回。Phase-4 Deferred 总裁决不受影响。
本项目第三次'下游核实推翻上游结论'——多轮验证纪律双向起效。
2026-06-12 09:01:53 +08:00
shaw
b3261c94ea
docs(phase-4): 依赖测绘 + Phase-4 整包搬家 Deferred 裁决
...
双视角评审实测证伪整包搬家可行性前提(go build 证实 import cycle):
- openai 子系统实为 46 文件 65K 行(含 69 白盒测试),非摸底称的 7168 行单文件
- 双向硬耦合:正向 178 符号/64 未导出;反向 57 符号经 6 个核心文件结构级引用
- 69 个 openai 测试 100% 白盒,move 即破 gate,无黑盒等价锚点
- 循环论证(L2 触发=搬家完成、搬家收益=为 L2 铺路)+ 零拉动信号
裁决:交付 C-C 依赖测绘,Phase-4 标 Deferred + 可观测触发条件。
架构债务发现:AccountRuntimeBlocker 误命名 openai 专属、实为通用调度依赖。
含 Phase-3 PHASE_SUMMARY 归档。
2026-06-12 08:46:02 +08:00
shaw
625c691b63
refactor(platform-seam): 默认模型 ID 同构 switch 收敛为单一来源
...
handler 与 admin_service 各持一份逐分支同构的平台默认模型 switch(必须人工同步)。
提取 service.DefaultModelIDsForPlatform 为单一来源 + 表驱动测试;
原函数改单行委托(调用点零改动)。含 Phase-3 审计报告归档(零 P0/P1,突变 3/3 捕获)。
2026-06-12 00:58:14 +08:00
shaw
f08f9111e5
refactor(platform-seam): gatewayplatform 接缝——Provider/Registry + 两处 Forward 分发替换
...
经双视角评审裁决的收窄版 Phase-3 接缝(零行为变更):
- internal/gatewayplatform:Provider{Platform,Forward} 两方法 v1 接口 +
ForwardRequest{Parsed,Body,IsStickySession,SessionGroupID,SessionKey} +
构造期注册 Registry(重复 panic,运行期并发只读)
- 3 个单语句直返 adapter(anthropic/antigravity/gemini,错误零包裹——
BetaBlockedError/PromptTooLong 的 errors.As 链由 T4 特征化守护)
- Messages 端点两处平台分发改 registry 查找;Type!=APIKey 条件保留调用点
- OpenAI(独立 handler)、v1beta 端点、内核 internal/plugin 零触碰
门禁:T1-T5 特征化全绿、安全网 45 包、bench allocs 全部持平(266/329/93/134)。
2026-06-12 00:27:10 +08:00
shaw
57a2e7184b
test(platform-seam): Phase-3 前置特征化 T1-T5——平台分发行为锁定
...
为 gatewayplatform 接缝(:444/:794 分发改 registry)建立等价性 gate:
- T1 :794 路由矩阵(antigravity×{非APIKey,APIKey},锁定 Type!=APIKey 真实条件)
- T2 :444 gemini→ForwardGemini 参数逐一断言 + action 契约(service 层)
- T3 粘性 session 选项端到端透传(DeleteSessionAccountID 参数 + force_cache_billing)
- T4 BetaBlockedError/PromptTooLong 错误链(adapter 包裹即红)
- T5 antigravity forward 基准 ×2 纳入基线(旧基准零漂移后重采)
含 Phase-3 设计双视角评审归档(修正摸底三处事实错误、接口砍至 2 方法、OpenAI 剔出本期)。
2026-06-12 00:07:02 +08:00
shaw
0df861f450
chore: 收窄 backend/scripts 白名单至 bench-baseline.sh(保持既有本地脚本忽略状态)
2026-06-11 23:01:57 +08:00
shaw
7d67eb083a
docs(refactor): 插件化改造各阶段完成报告与审计记录归档
...
issues/plugin-refactor/:Phase-0~2 的任务完成报告、阶段总结、
两轮内核审计报告、Phase-2 接缝设计双视角评审与实施后对抗审计、调用点清单。
2026-06-11 23:00:19 +08:00
shaw
1cdab6f858
refactor(seams): Phase-2 接缝——payment 注册表化 + 网关 pre-flight 钩子链
...
设计经双视角架构评审裁决(零行为变更,特征化测试先行锁定):
- payment/provider:factory switch → 包内私有构造器注册表(init 自注册);
unknown-key 文案与 ApplicationError 透传逐字节等价(前端 i18n 依赖)
- internal/gatewayhook:协议无关 pre-flight 钩子链(panic 隔离、error 默认
fail-open、首 Blocked 短路、空链零分配);Decision→格式化保留在各调用点
- 8 个 HTTP moderation 调用点收敛经链(各点入参表达式/格式化函数逐一保留),
WebSocket 两点按裁决保持原路径;moderation 为 Wire 装配的核心钩子
- 新增 7 个拦截格式特征化测试(5 种 HTTP 格式差异 + WS turn-2 + fail-open)
实施后对抗审计零 P0/P1,突变实验 4/4 被测试捕获;bench allocs 全部零增加。
2026-06-11 22:59:47 +08:00
shaw
9be516448e
feat(devkit): Phase-1.5 模块脚手架 + 前端模块可观测页 + 作者指南
...
- tools/newmodule + make new-module ID=job.foo:开箱即编译即测试的模块骨架
(ID 校验复用内核规则、渲染必经 gofmt、失败原子回滚、显式插装提示)
- 前端 /admin/modules 只读页:列表/状态徽章/错误悬浮/中英 i18n + vitest
- docs/plugin-architecture/MODULE-AUTHOR-GUIDE.md:模块作者指南
(生命周期契约/配置子树/插装清单/plugintest 用法/开发调试工作流闭环/常见坑)
2026-06-11 22:59:07 +08:00
shaw
8ba2fbd786
feat(plugin): Phase-1/1.5 进程内插件内核 + 开发套件后端
...
Caddy 式进程内模块系统(详见 docs/plugin-architecture/MODULE-AUTHOR-GUIDE.md):
- internal/plugin:命名空间注册表(init 注册/重复 panic)、Provision→Validate→Start→Stop
生命周期(Start 半途逆序回滚、Stop 逆序+ctx deadline)、Host 四项 ports 能力面、
modules: 配置子树(enabled 三态;viper 含点 key 手工提取)、Runtime 状态机
- internal/plugin/plugintest:模块测试夹具(NewHost Options + RunLifecycle)
- internal/modules:standard/imports.go 唯一插装清单 + job.hello 示例模块(默认 disabled)
- Wire/main 接入:Build+Start 失败 fail-fast(显式 Cleanup 防 leader 锁泄漏)、
runtime.Stop 在 cleanup 并行组首位(先于 Redis/Ent)
- admin 可观测:GET /api/v1/admin/modules(只读,错误文本脱敏)
- 默认配置零行为变更(Phase-0 安全网 + bench allocs 零漂移验证)
含两轮对抗式审计修复(1×P1 启动失败泄漏 leader 锁 + 11×P2)与回归测试。
2026-06-11 22:58:51 +08:00
shaw
f9fac7acbe
test(safety-net): Phase-0 回归安全网——特征化/不变量测试 + 基准基线 + CI 门禁
...
插件化改造前置:把'绝不回归'变成机器可验证的硬约束。
- 透传特征化:anthropic 逐字节/SSE 逐事件、openai、gemini 路径与错误透传
- 计费不变量:5m/1h 双档缓存价、倍率叠加顺序、overages、端到端金额与配额增量
- 调度不变量:粘性会话、failover 10/3/3 完整循环、并发槽配平、等待队列
- 热路径基准基线 + scripts/bench-baseline.sh(allocs 严格/ns 15%/基准缺失 FAIL)
- Makefile test-invariants 目标 + CI invariants job;修复失效的 test-e2e 脚本引用
- .gitignore:放行 backend/scripts 与 docs/plugin-architecture(既有白名单模式)
注:本分支按整体门禁验证(部分测试夹具引用后续提交的签名,中间提交不保证独立编译)。
2026-06-11 22:57:54 +08:00
github-actions[bot]
e34ad2b194
chore: sync VERSION to 0.1.136 [skip ci]
2026-06-10 07:02:12 +00:00
shaw
0acf00c4a1
Add admin compliance acknowledgement gate
v0.1.136
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
2b1c5f8563
Merge pull request #3186 from jianjianai/fix/account-group-scheduler-indexes
...
优化账号分组调度索引 / Add two concurrent composite indexes
2026-06-10 09:58:31 +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
jjaw
30c00a91d8
优化账号分组调度索引
2026-06-10 00:59:50 +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
72c112164e
fix(frontend): bedrock_cc_compat toggle not persisting on reload
...
apiToForm read bedrock_cc_compat as Record<string, boolean> (nested map)
but formToAPI saves it as a plain bool. Reading true["anthropic"] returns
undefined, so the toggle always appeared off after save.
Align the read path with the write path: fc?.bedrock_cc_compat === true.
2026-06-10 00:18:28 +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
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
shaw
63d95b4ec7
chore: updeta sponsors
2026-06-09 19:41:29 +08:00
Wesley Liddick
434af38fd5
Merge pull request #3140 from DaydreamCoding/feat/admin-users-apikey-group-filter
...
feat(admin): /admin/users 新增按用户 API Key 所在分组过滤
2026-06-09 10:49:11 +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
shaw
be01744565
chore: update sponsors
2026-06-08 20:15:15 +08:00
shaw
b7cfe24626
chore: update README
2026-06-08 16:41:47 +08:00
shaw
acbcb50de1
chore: update README
2026-06-08 15:43:19 +08:00
Wesley Liddick
54b1c7fc31
Merge pull request #3113 from learnerLj/main
...
fix(openai): Chat Completions 转 Responses 时保留 prompt_cache_key
2026-06-08 15:20:28 +08:00
Jiahao Luo
d251487da8
fix(openai): propagate prompt cache key for chat completions
2026-06-08 11:13:18 +08:00
github-actions[bot]
0aad603013
chore: sync VERSION to 0.1.135 [skip ci]
2026-06-08 01:47:21 +00: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