mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-12 04:07:25 +00:00
fix(channels): 四渠道修复 —— qoder 裸 token 领取 / trae+buddy 非流式 / opencode 目录 / 隐藏适配器
生产实测逐渠道排查(2026-10-19):
* qoder:PKCE 设备码流无 register 第二跳,落库凭据是裸 token 字符串;
qoderClaim 硬要求结构化 table 导致「缺少凭据对象」(而 account_test
走 token 路径正常 —— 自相矛盾状态)。改为非空裸 tok 就地包
{access_token=tok};补 TestQoderClaimAcceptsBareTokenCredential。
* trae(SOLO 自装适配器):上游对非流式请求也回 SSE(event: 前缀帧),
transform_response 不识别 → 整个 body 原样透传 → Go unmarshal 报
invalid character 'e'。补 aggregate_solo_sse 聚合。
* buddy(CodeBuddy):上游 400 11101 只支持流式。transform_request 强制
stream=true;transform_response 补 SSE 聚合(tool_calls 按 index 拼分片)。
* provider 流式:真实 tool-call 片段之后出现 finish_reason=stop 时归一为
tool_calls(trae 实测如此发);buddy/trae 不再序列化空 tool_calls 表。
* opencode:远端目录端点改为 /zen/v1/models(裸 /v1/models 回 HTML);
兜底目录同步 2026-10-19 实测(space-bunny-free 410 下架等 5 项变化)。
opencodezen 适配器 v1.1.0:会话亲和(client_session / 首 user 消息指纹
分桶),保留免费层门禁四要素。
* 内核:适配器可声明 adapter.hidden = true 退出用户可见列表;被源引用的
隐藏适配器保持可见(源编辑器要回显当前值)。opencodezen 默认隐藏。
* channels UI:切渠道立即清空账号/模型区 + 响应代际校验,修复 qoder 账号
闪现在 opencode 卡片下的渲染竞态。
* channels request_end hook:挂接丢失的 isModelGone/recordDeadModel ——
真实 404(如 codearts GLM-5.3 "The model is not registered")现在会进
deadModels,不再每轮 404 仍可选中。
This commit is contained in:
49
internal/lua/vm_hidden_test.go
Normal file
49
internal/lua/vm_hidden_test.go
Normal file
@ -0,0 +1,49 @@
|
||||
package lua
|
||||
|
||||
import "testing"
|
||||
|
||||
// hidden=true 的适配器:不被任何源引用时从 ListAdapters 消失;被引用时保持可见。
|
||||
// 这个行为支撑"内部适配器默认隐藏"的约定(opencodezen 是第一个使用者)。
|
||||
func TestAdapterHiddenFlag(t *testing.T) {
|
||||
vm := NewVM(freshAdapterDir(t))
|
||||
if err := vm.Start(); err != nil {
|
||||
t.Fatalf("start: %v", err)
|
||||
}
|
||||
defer vm.Stop()
|
||||
const src = `
|
||||
local adapter = {}
|
||||
adapter.name = "secretone"
|
||||
adapter.version = "1.0.0"
|
||||
adapter.endpoint = "/chat/completions"
|
||||
adapter.hidden = true
|
||||
function adapter.transform_request(raw) return raw end
|
||||
function adapter.transform_response(raw) return raw end
|
||||
return adapter
|
||||
`
|
||||
if err := vm.LoadAdapterSource("secretone", src); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 未被引用 → 隐藏
|
||||
vm.SetHiddenRefs(nil)
|
||||
for _, a := range vm.ListAdapters() {
|
||||
if a.Name == "secretone" {
|
||||
t.Fatal("hidden adapter must not be listed when unreferenced")
|
||||
}
|
||||
}
|
||||
// 被引用 → 可见
|
||||
vm.SetHiddenRefs([]string{"secretone"})
|
||||
found := false
|
||||
for _, a := range vm.ListAdapters() {
|
||||
if a.Name == "secretone" {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("hidden adapter must stay listed while referenced by a source")
|
||||
}
|
||||
// transform 路径不受 hidden 影响:隐藏 ≠ 禁用
|
||||
out, err := vm.Transform("secretone", "transform_response", `{"x":1}`)
|
||||
if err != nil || out == "" {
|
||||
t.Fatalf("hidden adapter must still transform: %v %q", err, out)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user