面向多llms订阅者,部署在内网,实现一次配置多个服务共同使用的效果。支持指定模型或auto模式,按照配置的优先级选择可用模型提供服务
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(types): 统一线格式 v2 最大集合 + 对外输出 golden 基线 Phase 1:内核定义市面所有主流协议字段的**并集**作为唯一内部格式, 适配器按需取用;内核不再携带任何协议形状。 - internal/types/maxwire.go:UnifiedRequest(21 字段,v1 的 10)、 UnifiedResult(11,v1 的 8)、UnifiedDelta。覆盖 openai/anthropic/ gemini/ollama/deepseek 各自必需字段(system 顶层、top_k、stop_sequences、 thinking 预算、parallel_tool_calls、response_format、safety/citations…)。 - 只带**语义**不带**容器**:generationConfig/systemInstruction/options/ num_predict/maxOutputTokens 等协议专属形状一律不进统一格式,由适配器 自行装填。测试 TestNoProtocolContainerLeak 钉死这条。 - 修掉 v1 的私有字段泄漏:disable_thinking/extra_body 曾是内核私有字段, 却被序列化进交给适配器的 body,导致 10 个适配器各自写 req.disable_thinking = nil 清理。v2 用 thinking 语义字段替代, TestNoKernelPrivateFieldLeak 为回归。 Phase 0:建立对外输出的**字节级** golden 基线(.snapshots/), 因为现有 e2e 只有 strings.Contains 宽松断言,无法证明 Phase 2 把 OpenAI wire 移交给适配器 serializer 后输出字节未变。 - e2e/wire_golden_test.go:非流式/流式/生图三个 golden, 比对前 scrub 掉 id 与 created(每请求变化),其余逐字节比对。 - 反向验证:注入 chat.completion.chunk.DRIFTED 漂移后 golden 确实失败 (证明它不是永远通过的空壳),随后完整恢复。 - 稳定性:连跑 3 次全绿。 验证:go test -tags luajit ./internal/types/ ./e2e/ -run 'TestMax|TestNo|TestWireGolden' 全绿。 | 6 天前 | |
chore(gui): 版本号 1.9.6 → 1.9.7 | 11 天前 | |
fix(channels,provider): 渠道模型不可用 + 额度异常的三个根因 ## 背景 用户报三问题:① channel 注册的模型无法使用;② 额度显示依旧异常; ③ 其他渠道应也存在类似问题。三条全部核实并给出结论(③ 见文档)。 ## ① 网关解不开 源名:模型名 限定名(internal/provider/registry.go) ResolvePinned 用 strings.IndexAny(model, "-:/") 找**第一个**分隔符。 而渠道源名形如 channels-trae-b8dd6b3df30e(**含 -**),于是 channels-trae-b8dd6b3df30e:Doubao-Seed-2.1-Pro 被切成 src="channels"、model="trae-b8dd6b3df30e:Doubao-Seed-2.1-Pro" ⇒ 源名永不匹配 ⇒ Resolve() 返回 nil ⇒ 客户端看到 model "..." is not configured。 **为什么这个写法必须支持**:本实例有 **44 个模型被多源同时提供** (glm-5.2 由 6 个源提供),WebUI 的模型下拉框用 源名:模型名 作为 option value 是**有意设计** —— 用户必须能指定"从哪个源调用"。 修法:抽 splitPinned(),**按已知源名做最长前缀匹配**(源名是已知集合, 这是唯一可靠办法),保留旧 -:/ 兜底以兼容非源名形态。 EffectiveModel 同步修(同一拆分规则,避免两处漂移)。 ## ② trae 适配器三连错(internal/lua/plugins/channels.lua) 三个错误逐层叠加,每个都被上一层掩盖: **(a) 没有 build_headers** ⇒ 内核兜底发 Authorization: Bearer, 而 trae 推理端点要 Cloud-IDE-JWT + 设备身份头 ⇒ 401「We're sorry, but we are not able to authenticate you」。 → 与上一轮「额度不可用」是**同一根因的两个出口**(额度端点修了、推理端点漏了)。 教训:修"某一族请求的鉴权"时,必须把该族的**所有出口**列出来逐个对齐。 **(b) header 常量的值是错的**(照参考 trae-product.ts 的 TRAE 配置逐项核对): · X-App-Id 抄成 6eefa6c9,真实是 6eefa01c-1036-4c7e-9ca5-d891f63bfcd8 · app_version_code 用了 0.1.52,真实是**日期式** 20260811 ⇒ 上游 4001 bad request: binding: expr_path=app_version_code, cause=parameter type does not match binding data **(c) 流式转换完全不对**:TRAE 是 **SOLO 自定义 SSE**: event:output → data:{"response":"###","reasoning_content":null,...} 正文在 response,推理在 reasoning_content。 · 套 __prelude.openai_stream_chunk ⇒ 无 choices ⇒ empty stream · 改成 OpenAI 外壳 {choices:[{delta}]} **仍然空** —— 内核 json.Unmarshal(unified, &UnifiedChunk) 解的是**扁平结构**,外壳字段全被丢弃 ⇒ 必须输出扁平 {content, reasoning_content, usage, done, finish_reason}。 ⚠️ 内核只把 data: 行交给适配器(event: 行在 provider.go 被丢弃), 因此判别帧类型只能靠**内容特征**(response / reasoning_content / finish_reason / prompt_tokens),拿不到 event 名。 ## ③ 余额恒为 0(同文件 balance.total_fn) 读的是 p.credits_limit(pack **顶层**)—— 该字段**根本不存在**。 真实路径是 pack.entitlement_base_info.quota.credits_limit (参考 trae-credits.ts:341)+ pack.usage.credits_amount。 实测上游:免费(无该字段) / 每月登录赠送(500) / 签到奖励(100) ⇒ 实际 600。 修法:读嵌套路径 + 保留顶层兼容 + usage_summary.{total,consumed}_amount 兜底。 修后余额 600 → 实测 598.516(真实扣减)。 ## ④ 夹具与生产形状不一致(internal/core/channels_trae_test.go) 夹具原先返回**扁平** {"Token":...},与生产 {"Result":{"Token":...}} 不符 ⇒ 「代码只读顶层」这个缺陷在夹具里**恰好是对的**,所有 trae 判据都绿。 **夹具形状错 = 判据必然虚假通过**。这是 ExchangeToken 缺陷藏了两轮的原因。 ## 判据(新增,变异 4/4 咬住) - internal/provider/registry_pinned_name_test.go(4 用例) - internal/core/channels_trae_chat_headers_test.go(3 条) - internal/core/channels_trae_solo_sse_test.go(2 条) - internal/core/channels_trae_credits_hdr_test.go(1 条) - internal/core/channels_trae_exchange_shape_test.go(2 条) ## 文档 docs/channel-repair-plan.md:现状快照(生产实测)+ 各渠道缺陷矩阵 + 后续计划(P0-P4)。**如实记录**:其余 4 个渠道(zcode/cline/gemini/qoder) 有同类缺陷风险,但**账号数均为 0、无法做生产验证**。 ## 生产已实测 - channels-trae-...:Doubao-Seed-2.1-Pro → 80 帧,正文 27 + 推理 299 - channels-trae-...:glm-5.2 / channels-buddy-...:hy4-preview → OK - credits/status → active:true, dailyCredit:100, todayCheckedIn:true - credits/balances → total:598.516 credits | 12 分钟前 | |
chore(main): 回流 release/v2.0.x(v2.0.12)—— 内容对齐,main 无独有内容 按发布纪律回流。**注意这是内容对齐而非 merge**,理由与依据: 1. 纪律禁止 merge 回主干,因为 merge 会把发布分支的**版本号变更**带进 main。 本项目版本号**只由 git describe --tags 推导**(Makefile VERSION), 仓库里没有任何文件存放版本号 ⇒ 回流不存在版本污染风险。 2. 逐项核对确认 **main 是 release 的内容严格子集**: - main 独有的**文件**:0 个; - internal/lua/plugins.go / internal/core/kernel_actions.go 等内核文件 main 独有行数:0; - deploy.sh 那 14 行只是 emoji 清理(release 刻意去掉了 emoji); - channels.lua 那 333 行是**旧版内容**(旧 exports 表、旧模型名单)。 - main 独有的 9 个提交按 patch-id **全部已在 release 中等效存在** (git cherry 逐条列出均为 -,即已合入)。 3. 故回流 = 把 release 的内容带到 main,等价于"只捡拾修复、不带版本号", 且不会丢任何 main 独有的修复。 本次带回 v2.0.12 的全部内容(37 个提交): - 源串行 + 按模型节流(照 model-gate) - 已失效模型存储 + 远端目录闸门 - 余额分档选号 - 模型能力元数据(models.dev,isFree 权威判定) - **凭据续期修复**(此前恒报 ok:true 却一个请求都不发) - 通用件 TTL 缓存 + 串行锁;account_test/account_adopt/account_delete 修正 - 内核级:出站授权持久化重启后不生效、__llmsproxy_plugin_dir ground truth 校验:git diff release/v2.0.x = 0 行;go build -tags luajit ./... 通过。 | 3 天前 | |
fix(channels,provider): 渠道模型不可用 + 额度异常的三个根因 ## 背景 用户报三问题:① channel 注册的模型无法使用;② 额度显示依旧异常; ③ 其他渠道应也存在类似问题。三条全部核实并给出结论(③ 见文档)。 ## ① 网关解不开 源名:模型名 限定名(internal/provider/registry.go) ResolvePinned 用 strings.IndexAny(model, "-:/") 找**第一个**分隔符。 而渠道源名形如 channels-trae-b8dd6b3df30e(**含 -**),于是 channels-trae-b8dd6b3df30e:Doubao-Seed-2.1-Pro 被切成 src="channels"、model="trae-b8dd6b3df30e:Doubao-Seed-2.1-Pro" ⇒ 源名永不匹配 ⇒ Resolve() 返回 nil ⇒ 客户端看到 model "..." is not configured。 **为什么这个写法必须支持**:本实例有 **44 个模型被多源同时提供** (glm-5.2 由 6 个源提供),WebUI 的模型下拉框用 源名:模型名 作为 option value 是**有意设计** —— 用户必须能指定"从哪个源调用"。 修法:抽 splitPinned(),**按已知源名做最长前缀匹配**(源名是已知集合, 这是唯一可靠办法),保留旧 -:/ 兜底以兼容非源名形态。 EffectiveModel 同步修(同一拆分规则,避免两处漂移)。 ## ② trae 适配器三连错(internal/lua/plugins/channels.lua) 三个错误逐层叠加,每个都被上一层掩盖: **(a) 没有 build_headers** ⇒ 内核兜底发 Authorization: Bearer, 而 trae 推理端点要 Cloud-IDE-JWT + 设备身份头 ⇒ 401「We're sorry, but we are not able to authenticate you」。 → 与上一轮「额度不可用」是**同一根因的两个出口**(额度端点修了、推理端点漏了)。 教训:修"某一族请求的鉴权"时,必须把该族的**所有出口**列出来逐个对齐。 **(b) header 常量的值是错的**(照参考 trae-product.ts 的 TRAE 配置逐项核对): · X-App-Id 抄成 6eefa6c9,真实是 6eefa01c-1036-4c7e-9ca5-d891f63bfcd8 · app_version_code 用了 0.1.52,真实是**日期式** 20260811 ⇒ 上游 4001 bad request: binding: expr_path=app_version_code, cause=parameter type does not match binding data **(c) 流式转换完全不对**:TRAE 是 **SOLO 自定义 SSE**: event:output → data:{"response":"###","reasoning_content":null,...} 正文在 response,推理在 reasoning_content。 · 套 __prelude.openai_stream_chunk ⇒ 无 choices ⇒ empty stream · 改成 OpenAI 外壳 {choices:[{delta}]} **仍然空** —— 内核 json.Unmarshal(unified, &UnifiedChunk) 解的是**扁平结构**,外壳字段全被丢弃 ⇒ 必须输出扁平 {content, reasoning_content, usage, done, finish_reason}。 ⚠️ 内核只把 data: 行交给适配器(event: 行在 provider.go 被丢弃), 因此判别帧类型只能靠**内容特征**(response / reasoning_content / finish_reason / prompt_tokens),拿不到 event 名。 ## ③ 余额恒为 0(同文件 balance.total_fn) 读的是 p.credits_limit(pack **顶层**)—— 该字段**根本不存在**。 真实路径是 pack.entitlement_base_info.quota.credits_limit (参考 trae-credits.ts:341)+ pack.usage.credits_amount。 实测上游:免费(无该字段) / 每月登录赠送(500) / 签到奖励(100) ⇒ 实际 600。 修法:读嵌套路径 + 保留顶层兼容 + usage_summary.{total,consumed}_amount 兜底。 修后余额 600 → 实测 598.516(真实扣减)。 ## ④ 夹具与生产形状不一致(internal/core/channels_trae_test.go) 夹具原先返回**扁平** {"Token":...},与生产 {"Result":{"Token":...}} 不符 ⇒ 「代码只读顶层」这个缺陷在夹具里**恰好是对的**,所有 trae 判据都绿。 **夹具形状错 = 判据必然虚假通过**。这是 ExchangeToken 缺陷藏了两轮的原因。 ## 判据(新增,变异 4/4 咬住) - internal/provider/registry_pinned_name_test.go(4 用例) - internal/core/channels_trae_chat_headers_test.go(3 条) - internal/core/channels_trae_solo_sse_test.go(2 条) - internal/core/channels_trae_credits_hdr_test.go(1 条) - internal/core/channels_trae_exchange_shape_test.go(2 条) ## 文档 docs/channel-repair-plan.md:现状快照(生产实测)+ 各渠道缺陷矩阵 + 后续计划(P0-P4)。**如实记录**:其余 4 个渠道(zcode/cline/gemini/qoder) 有同类缺陷风险,但**账号数均为 0、无法做生产验证**。 ## 生产已实测 - channels-trae-...:Doubao-Seed-2.1-Pro → 80 帧,正文 27 + 推理 299 - channels-trae-...:glm-5.2 / channels-buddy-...:hy4-preview → OK - credits/status → active:true, dailyCredit:100, todayCheckedIn:true - credits/balances → total:598.516 credits | 12 分钟前 | |
chore(main): 回流 —— VNC 兜底登录真正可用(放开 browser-stack 不需要的加固 + 修 3 个插件缺陷) 按纪律先在 release/v2.0.x 提交,再内容对齐回 main。 校验:git diff release/v2.0.x = 0 行。 | 2 天前 | |
chore(main): 回流 release/v2.0.x(v2.0.12)—— 内容对齐,main 无独有内容 按发布纪律回流。**注意这是内容对齐而非 merge**,理由与依据: 1. 纪律禁止 merge 回主干,因为 merge 会把发布分支的**版本号变更**带进 main。 本项目版本号**只由 git describe --tags 推导**(Makefile VERSION), 仓库里没有任何文件存放版本号 ⇒ 回流不存在版本污染风险。 2. 逐项核对确认 **main 是 release 的内容严格子集**: - main 独有的**文件**:0 个; - internal/lua/plugins.go / internal/core/kernel_actions.go 等内核文件 main 独有行数:0; - deploy.sh 那 14 行只是 emoji 清理(release 刻意去掉了 emoji); - channels.lua 那 333 行是**旧版内容**(旧 exports 表、旧模型名单)。 - main 独有的 9 个提交按 patch-id **全部已在 release 中等效存在** (git cherry 逐条列出均为 -,即已合入)。 3. 故回流 = 把 release 的内容带到 main,等价于"只捡拾修复、不带版本号", 且不会丢任何 main 独有的修复。 本次带回 v2.0.12 的全部内容(37 个提交): - 源串行 + 按模型节流(照 model-gate) - 已失效模型存储 + 远端目录闸门 - 余额分档选号 - 模型能力元数据(models.dev,isFree 权威判定) - **凭据续期修复**(此前恒报 ok:true 却一个请求都不发) - 通用件 TTL 缓存 + 串行锁;account_test/account_adopt/account_delete 修正 - 内核级:出站授权持久化重启后不生效、__llmsproxy_plugin_dir ground truth 校验:git diff release/v2.0.x = 0 行;go build -tags luajit ./... 通过。 | 3 天前 | |
fix(plugin): /api/ui-inject 的 stages 漏掉 chain_step + 忽略临时构建目录 部署到线上时用隔离实例(独立端口 18099 + 独立 config/runtime/adapter 目录) 发真实请求验证,抓到的第三个 bug。 ## bug:discovery 文档漏掉新 stage handlePluginUI 的响应里 stages 是**字面写死的三个**。加 chain_step 时只改了 lua.AllStages,没改这里,于是插件作者读 GET /api/ui-inject 会看到 ["request_start","routed","request_end"],**合理地得出结论:没有 chain_step 这个 stage**。stage 本身是注册好的、也确实在触发,只是没被声明。 改成从 lua.AllStages 派生——AllStages 是唯一定义顺序的地方,让它保持唯一。 ★ 而我原来的测试断言 len(view.Stages) != 3,**断言本身是 bug 的保护伞**: 它把"三个"固化成了期望值,于是新增第四个 stage 时测试全绿、bug 上线。 现在断言改为「与 AllStages 等长且逐项相同」,并显式要求 chain_step 在其中。 新增 stage 而忘了声明,这类问题会立刻红。 ## 顺带:.gitignore 补上临时构建目录 .probe/ 和 .build-work/ 是我调试时当 GOTMPDIR 和临时二进制用的,之前每轮 手工删,这轮差点提交进去 9.5MB 的二进制。 ## 部署验证留档 隔离实例跑真实 chat(158 prompt / 13 completion / 128 cache_hit),计费插件 算出 0.000688,与手算 (158-128)*1e-5 + 128*1e-5*0.1 + 13*2e-5 **逐位吻合**。 ★ 第一次手算我按全价算成 0.00184,一度以为插件算错了——查审计记录才看到 cache_hit_tokens。**算钱不对时先查输入再怀疑实现**,而我忘的恰是刚修的折扣。 ## 验证 351 个测试全绿;变异(stages 改回硬编码三个)被 TestUIInjectServesPluginUI 抓住,3 条断言同时红。 | 15 天前 | |
feat(packaging): core distribution packages (deb + rpm + tar.gz) via nfpm Previously only the Electron GUI had installers; server admins had to build the core by hand ( make build -> bare binary). This adds a first-class server distribution: - make core-dist -> packaging/core-dist.sh -> cmd/build/dist/ llmsproxy_<ver>_amd64.deb (systemd unit + adapters + example config) llmsproxy-<ver>.x86_64.rpm llmsproxy-<ver>-linux-amd64.tar.gz - nfpm config (packaging/nfpm.yaml): binary to /usr/bin, systemd unit with the measured memory tuning (GOGC=50, MALLOC_ARENA_MAX=2) baked in, Lua adapters to /usr/share/llmsproxy/adapters, repo's config.yaml as the example. - postinst seeds /etc/llmsproxy/config.yaml on first install and keeps existing runtime state across reinstalls; prerm stops the service on removal. Gotchas handled: nfpm v2 here does not render {{ .Env.VERSION }}, so the script stamps the version into a throwaway config copy; and under set -o pipefail the idiom strings | grep -q is broken (grep -q closes the pipe and strings dies on SIGPIPE -> spurious 141), so the symbol sanity-gate stages strings in a temp file. README (zh/en) updated: memory figures replaced with production-measured 32-35 MB settled (was 37-42), and the packaging docs now describe core-dist and the dockerized Windows build. | 1 个月前 | |
docs: 契约 v2 文档收尾(Phase 7) 用户要求的收尾。三份文档与代码对齐。 ## docs/lua-adapters.md - 新增 §4「出向序列化钩子(契约 v2)」:serialize_response / serialize_open_preamble / serialize_chunk / serialize_close / serialize_done_marker。核心语义:**声明即完全取代**内核的 OpenAI 兜底, 不是叠加 —— 适配器输出里不会有内核补的 OpenAI 字段(R2/R5)。 - §8 标题与内容从 disable_thinking 改为中立的 thinking 预算: {enabled, budget_tokens},由适配器映射到目标协议。v1 的 disable_thinking/extra_body 是内核细节泄漏进适配器请求体的典型 (迫使 10 个适配器各写一行清理),已记明已被取代。 - §7 最小适配器示例同步改成映射中立 thinking 字段。 ## docs/plugins.md - §5.4 定时任务(PLUGIN.schedule):every/at/jitter/timeout 字段表 + **内核 ticker 驱动、浏览器关着也跑** + 任务与钩子同一个 VM(写 plugin.state 立即可见于请求)+ 卡死则停用该插件(不能中断 Lua 的 能力边界)。 - §5.5 自定义对外挂载点:plugin.http 声明同时可在 /api/plugins/http/、 /plugins/、/v1/plugins/ 三处访问;命名空间约束与内核路由冲突拒绝。 - §5.6 运行时安装/更新适配器(token 轮换)+ 三条安全规则。 - §6.1 更正:某个卡住的钩子/任务只卡**它自己**那个插件的钩子(跨插件 并行),原文写的是"卡住所有插件"。 - §9 对比表补周期任务/对外端点两行,钩子列表补 serialize_*。 ## README - disable_thinking 章节 → thinking 预算(中立字段 + 各适配器映射)。 - 适配器协议示例补 serialize_* 出向钩子。 - 特性列表与测试覆盖描述同步。 | 6 天前 | |
chore(adapters): 移除非官方调用方式的适配器,保留官方适配器与模板 移除 4 个靠伪造客户端身份/绕过 WAF 才能工作的适配器,内核不再发行任何 非官方调用方式: - opencodezen / opencode / opencodego:靠 x-opencode-* 客户端指纹冒充官方 客户端;zen 免费池明确要求「free tier can only be used in OpenCode」 - agentrouter:伪造 Origin: qwen.ai + Referer + X-Requested-With 绕过阿里云 WAF 保留 12 个官方适配器(openai/deepseek/anthropic/gemini/github/groq/mistral/ ollama/kimicode/qwen38/sensenova/trae),其中 sensenova/qwen38 实测零伪装特征。 本地保留两处:adapters/_local_archive/(gitignored 非递归子目录,不加载) 与线上 /etc/llmsproxy/adapters/(adapter_dir 权威副本,cp -f 不删文件)。 测试同步:删除仅服务于被移除适配器的 11 个测试函数与 usage_cost_test.go; 改写 2 处借 opencode 之名的 provider 测试为用 openai 的 HTML 错误页压缩能力 验证同一契约(适配器钩子拥有错误格式、原文不外泄)。 验证:go test -tags luajit ./... 全绿;二进制内 x-opencode-client / QwenCode/0.2.0 / qwen.ai 等指纹字符串计数归零。 | 6 天前 | |
feat(zcode): 身份块适配器 + 修复调度器泄漏 + codearts 目录 + 备份裁剪泛化 ## 1. ★ zcode 身份块适配器(channels-zcode)—— 准入的唯一开关 参考实测(三账号 17 次请求):zcode 的 /zcode-plan/anthropic 通道做**请求体 内容检查**,system 缺官方身份块结构时直接 HTTP 405 + {"code":3012}: 无 system → 3012 ✗ 仅 cliPrefix(42 字符) → 3012 ✗ cliPrefix + stable(约 2898 字符)→ 200 ✓ ⇒ 判据是「身份块结构是否存在」,与 HTTP 头、版本号、频率、多轮历史、tools 声明、运行时全部无关。我们此前用通用 anthropic 适配器 ⇒ **即使拿到 zcode 账号也必然被拒**(现在 0 账号,但这是能不能用起来的前提)。 实现:插件自装 channels-zcode —— 读内核 anthropic.lua 执行取基座,**只覆盖 transform_request** 注入身份块(协议转换始终与 anthropic 那一份一致,不漂移): block[1] cliPrefix(42) / block[2] stable(2852) / block[3] Environment 段 / block[4] 调用方 system(**必须追加在最后**:上游看的是前缀结构) 只给最后一块打 cache_control(Anthropic 上限 4 断点,逐块打会占满预算) 日期块插入首条 user 的 content **数组**最前(拼进字符串会改变结构) 文本与参考**逐字节一致**(已核对:42 + 2856 = 2898)。 ★ 基座读不到时**响亮失败**,不静默退化 —— 否则会产出"身份块看着对、工具/图像 全没转换"的请求,上游可能 200 但模型拿不到工具定义,症状是"模型变笨了", 与准入毫不相干、排查完全跑偏。 判据 4 条 + 变异 2/2:不注入 → 报红;截断到 100 字符 → 报红。 另加"协议转换不退化"判据(工具 input_schema / 图像块存活)。 ## 2. ★★ 同一缺陷家族第 3 个实例:Close() 不停调度器 修完 on_unload 后全量回归 internal/lua **600s 超时**,goroutine 快照显示 **69 个卡在 stateSaver.loop 与 PluginRuntime.loop**。 根因:Runtime.Stop() **只在单插件 Unload 里调**,Close() 不调 ⇒ 每个插件的 调度循环在"进程关闭/测试结束"路径上永不停止。与 on_unload 完全同一形状。 修法:Close() 新增 stopSchedulersAll(),顺序 = 停调度 → 落盘 → on_unload (调度器必须停在落盘之前,否则它写一个已收尾的 state)。 ★ 顺带:Stop() 不幂等(裸 close 会 panic: close of closed channel), 两处都调之后可达 —— 用 sync.Once 加固。给函数加第二个调用点前先查幂等性。 实测 internal/lua 从 600s 超时 → 62s 通过。 ## 3. codearts 模型目录:补两个**必须 AK/SK 签名**的端点 codearts 有 10 个账号但目录里只有硬编码 1 个模型。参考打两个端点: ① opengw.../gateway/config → result.models(benefit) ② snap-access.../v1/model/builtin → builtinModels(常规) 而 refreshRemoteModels **只支持 Bearer** ⇒ 这两端点从来没被打过。 已加 ep.sign="codearts" 分支 + 两个解析形态 + opengw host 白名单。 判据:两端点各自真实命中 + 每请求带 SDK-HMAC-SHA256 头 + **合并**(非取其一)。 ## 4. TRAE PKCE 候选来源补齐(3 → 5) 参考 authCodeCandidates 有 5 个来源,我们只有 3(漏了 authCodeInfo 为 JSON 的 authCode 字段、以及**纯字符串**形态)。★ 且不能写成 a or b or c 链 —— jsonField 取不到时返回**空串**,Lua 里空串是真值,链会在第一个空串处短路。 判据 5 个参数化用例 + 变异 2/2 咬住(正是 or 链取不到的两个形态)。 ## 5. ★ 部署脚本:备份裁剪只修了一半("两处只修一处"再现) prune_adapter_backups 有完整实现(含数量硬上限),但**只针对 adapters.bak**; sync_plugins 同样每次建 plugins.bak.* —— 修了 adapters 的堆积、plugins 继续涨。 实测线上 plugins.bak **36 个**、/etc/llmsproxy 192M。 泛化为 prune_backups <prefix> + prune_all_backups(两个前缀都裁),加空前缀守卫。 判据不止逐字检查,而是**扫描脚本里所有 .bak.$(date) 创建点**,要求每个前缀都在 裁剪范围内 —— 将来新增第三种备份目录会立刻报红,而不是等它涨到几百兆。 变异 2/2 咬住(只裁 adapters / 去掉守卫)。 ## 6. 上游客观缺口钉成可执行判据(TestUpstreamGapsAreDocumented) qoder 加密端点需 .wasm(**参考仓库里也不存在**)、TRAE PKCE 参考**明确不支持**、 zcode 滑块需真实浏览器交互。写成判据:任何人(包括未来的我)想"补"这些能力, 必须先让判据失败 —— 即先推翻事实再动手。防的正是我前两轮的反复误判。 清理:channels-buddy.lua(0 字节历史遗留,每次启动报 must return a table)。 | 1 天前 | |
feat: LuaJIT worker-pool VM, multimodal/disable-thinking passthrough, WebUI redesign, DeepSeek V4 | 2 个月前 | |
feat: LuaJIT worker-pool VM, multimodal/disable-thinking passthrough, WebUI redesign, DeepSeek V4 | 2 个月前 |
项目 README 为空