mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-12 04:07:25 +00:00
fix(channels): 渠道鉴权头三修 + 源名契约 + 夹具形状判据
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 处)。
This commit is contained in:
@ -5,6 +5,45 @@ adapter.endpoint = "/v1/messages"
|
||||
adapter.headers = {
|
||||
["anthropic-version"] = "2023-06-01",
|
||||
}
|
||||
|
||||
-- ============================================================
|
||||
-- build_headers (鉴权头)
|
||||
-- ============================================================
|
||||
-- Anthropic 协议要 **x-api-key**,不是 `Authorization: Bearer`。
|
||||
-- 此前本基座只有一个静态 `anthropic-version`、**没有** build_headers ⇒ 内核
|
||||
-- 走兜底 `Authorization: Bearer <api_key>` ⇒ 上游一律 401/403:
|
||||
-- `{"type":"error","error":{"type":"authentication_error",
|
||||
-- "message":"invalid x-api-key"}}`
|
||||
-- 继承本基座的渠道源(channels-zcode 等)一有账号就会立刻暴露 —— 与 trae
|
||||
-- 修复前完全同型(静态头 + 内核 Bearer,缺协议要的那一个头)。
|
||||
--
|
||||
-- 三条纪律:
|
||||
-- ① 值取自内核注入的 `meta.api_key`(源的凭据),**绝不**写日志、不额外
|
||||
-- 放进返回值以外的任何地方;本函数只把它放进请求头。
|
||||
-- ② **不自己发 Authorization** —— 源级 headers 若已显式配置 Authorization,
|
||||
-- 重复发两种鉴权方案会让部分 Anthropic 兼容上游直接拒(歧义)。
|
||||
-- ③ `anthropic-version` 与静态头同值,保证「装了 hook」与「没装 hook」两种
|
||||
-- 路径产出同一份协议头,不会因为加了 hook 而少一个版本头。
|
||||
function adapter.build_headers(meta)
|
||||
local h = {
|
||||
["anthropic-version"] = "2023-06-01",
|
||||
}
|
||||
local key = ""
|
||||
if type(meta) == "table" then
|
||||
if type(meta.api_key) == "string" then key = meta.api_key end
|
||||
-- 兜底:个别调用方只给 source.meta.api_key(与 kimicode 同一约定)
|
||||
if key == "" and type(meta.source) == "table"
|
||||
and type(meta.source.meta) == "table"
|
||||
and type(meta.source.meta.api_key) == "string" then
|
||||
key = meta.source.meta.api_key
|
||||
end
|
||||
end
|
||||
if key ~= "" then
|
||||
h["x-api-key"] = key
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
-- INGRESS CLAIM (inbound dual of serialize_*): this adapter owns parsing of the
|
||||
-- client-facing POST /v1/messages request body. The kernel keeps a built-in
|
||||
-- Anthropic parser as its fallback (R5) — that is what an unconfigured
|
||||
|
||||
Reference in New Issue
Block a user