mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
P1-1 anthropic 基座补 build_headers(x-api-key + anthropic-version) 根因:基座只有静态 anthropic-version、没有 build_headers ⇒ 内核兜底发 Authorization: Bearer,而 Anthropic 协议要 x-api-key。 ★ 证据冲突(计划 P1-1 原文一半有误):zcode 的 /zcode-plan/anthropic/v1/messages 虽然**说 Anthropic 协议**,鉴权却是 Bearer <zcode_jwt>(参考 zcode-transport.ts:121-125;全仓 grep x-api-key = 0 次命中)。故 zcode 必须**显式覆盖** build_headers 回到 Bearer, 否则基座的正向修复会把它从"对"改成"错"。 内核改动:internal/provider/provider.go —— 兜底 Bearer 让位给 x-api-key, 避免同一请求带两套鉴权(部分 Anthropic 兼容上游对歧义鉴权直接 401)。 P1-2 channels-cline 的 build_headers 补 workos: 前缀 根因:参考 cline.ts 发 `Bearer workos:<jwt>`,而池里存的是第二步 register 换回的裸 token ⇒ 之前无 build_headers,内核兜底发裸 Bearer。 幂等:已带前缀(含大小写变体)不重复拼。 P1-3 channels-gemini 只确认不改 参考 gemini.ts:353-366 同样是 OAuth Bearer + 身份五头、刻意不发 x-goog-api-key ⇒ 我们现状本来就对。加判据把这个结论钉住,防下轮照 P1-1 的模子把它改坏。 P2 源名契约:仅 [A-Za-z0-9_-],禁 : 与 / 根因:: 与 / 是限定名分隔符,出现在源名里会让 `源名:模型名` 有两种都 自圆其说的切法,同一请求串在不同部署下可能路由到不同源,且**不报错**。 校验加在写入口 core.normalizeSource(硬拒,API 400);启动时只告警, 避免存量带 : 的源名让升级 brick 掉整个网关。 解析入口 splitPinned 不做校验(解析不该拒绝已有数据)。 P3 夹具形状判据(本轮最重要的一条) 根因:trae 的 Result 信封缺陷在扁平夹具下所有判据全绿,真实登录却报 「缺少 Token」—— 夹具形状错 ⇒ 判据必然虚假通过。 通用形状层:shapeFamilies 登记表,每族给 real/naive/fact/eval/assert, 断言 fact(real) 且 !fact(naive) 且 assert(eval(real))。 刻意**不比较 eval 输出形状**:trae 余额实现合法保留顶层兼容路径, 拿输出比对会把合法兼容判成错误;能区分真假的是 fact(额度在哪一层)。 另有仓库扫描:对特征明确的退化形状静态反查,需退化夹具时写 SHAPE-OK 豁免。 判据:11 个文件 / 30 用例。全部变异已验证会报红(9 处)。
69 lines
2.4 KiB
Go
69 lines
2.4 KiB
Go
package lua
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"testing"
|
||
)
|
||
|
||
// zcodeHarness 是与 runtimePlugins 等价的测试台,唯一差别是 **adapters 与
|
||
// plugins 目录互为兄弟**(`<tmp>/adapters` + `<tmp>/plugins`)。
|
||
//
|
||
// 为什么必须这样:installZcodeAdapter 要从「插件目录的父目录/adapters」读
|
||
// anthropic.lua 的源码,再把基座**内联**进适配器脚本(适配器沙箱没有 fs)。
|
||
// runtimePlugins 给 adapters/plugins 各用一个独立的 t.TempDir(),两个目录
|
||
// 不是兄弟 ⇒ zcode 安装期就报「读不到 anthropic.lua」而被跳过,适配器根本
|
||
// 不会出现(探针会如实报 ok:false,这本身是好事 —— 说明失败可见)。
|
||
//
|
||
// 生产里这两个目录是兄弟(config.PluginDir 与 config.AdapterDir 同级),
|
||
// 所以这个测试台更贴近真实布局。
|
||
func zcodeHarness(t *testing.T) (*VM, *Plugins) {
|
||
t.Helper()
|
||
root := t.TempDir()
|
||
adir := filepath.Join(root, "adapters")
|
||
vm := NewVM(adir)
|
||
if err := vm.Start(); err != nil {
|
||
t.Fatalf("vm: %v", err)
|
||
}
|
||
t.Cleanup(vm.Stop)
|
||
pdir := filepath.Join(root, "plugins")
|
||
if os.Getenv("LLMSPROXY_PLUGIN_DIR") == "" {
|
||
t.Setenv("LLMSPROXY_PLUGIN_DIR", pdir)
|
||
}
|
||
ps := NewPlugins(vm, pdir)
|
||
ps.SetOutboundHosts([]string{"127.0.0.1"})
|
||
// 同 runtimePlugins:关掉状态持久化,避免后台调度器写进生产 store。
|
||
ps.DisableStatePersistence()
|
||
|
||
src, err := bundledAdapters.ReadFile("plugins/channels.lua")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := ps.LoadSource("channels", string(src)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
// zcode 装不上时必须**响亮失败**,不能静默跳过 —— 否则判据会在
|
||
// 「适配器根本不存在」的情况下误判为通过(那正是 plan §3 第 1 条
|
||
// 说的假绿形态)。
|
||
res, err := ps.Call("channels", "__adapter_install_probe", map[string]interface{}{})
|
||
if err != nil {
|
||
t.Fatalf("__adapter_install_probe: %v", err)
|
||
}
|
||
j := probeJSON(t, res)
|
||
zc, ok := j["zcode"].(map[string]interface{})
|
||
if !ok {
|
||
t.Fatalf("探针未报告 zcode 装载结果: %v", j)
|
||
}
|
||
if zc["ok"] != true {
|
||
t.Fatalf("★ zcode 适配器装载失败: %v\n"+
|
||
" 注意 luac -p 对长字符串内的适配器代码无效(plan §3 第 1 条),"+
|
||
"必须以本探针为准", zc["err"])
|
||
}
|
||
if !vm.HasFn("channels-zcode", "build_headers") {
|
||
t.Fatal("zcode 装载后仍然没有 build_headers")
|
||
}
|
||
_ = fmt.Sprint()
|
||
return vm, ps
|
||
}
|