diff --git a/internal/core/channels_remove_source_perm_test.go b/internal/core/channels_remove_source_perm_test.go index fedc6ee..a1cd94f 100644 --- a/internal/core/channels_remove_source_perm_test.go +++ b/internal/core/channels_remove_source_perm_test.go @@ -48,6 +48,13 @@ func TestAccountDeleteRemovesItsSource(t *testing.T) { if !strings.Contains(joined, "remove_source") { t.Fatalf("记录里应点明是哪个内核动作被拒(便于给运维可操作提示),实得: %s", joined) } + // ★ 必须带上**真正的原因**(not granted),而不是"无返回"这类空话。 + // 内核桥失败时**第一个返回值是 nil、原因在第二个返回值里** —— + // 只接第一个返回值就会把原因丢掉(我第一版正是如此)。 + if !strings.Contains(joined, "not granted") { + t.Fatalf("记录里必须含内核给出的**真实原因**(not granted),"+ + "否则运维无从下手(只接 call 的第一个返回值就会丢掉原因);实得: %s", joined) + } t.Logf("✓ 撤源失败已可见: %s", joined) }) } diff --git a/internal/lua/plugins/channels.lua b/internal/lua/plugins/channels.lua index 81605e9..c50d88c 100644 --- a/internal/lua/plugins/channels.lua +++ b/internal/lua/plugins/channels.lua @@ -3654,14 +3654,14 @@ local function syncAccountSource(provider, accountId) -- ⚠ 这里失败**可容忍**:AddSource 是**同名 upsert**,add 会把旧的覆盖掉。 -- 但这正是它掩盖 remove_source 权限缺失的原因(纯删除路径才暴露), -- 故失败仍记一笔(低频,不会刷屏)。 - local rr = __llmsproxy_kernel.call("remove_source", { name = name }) - if not (rr and rr.ok) then + local rr, rerr = __llmsproxy_kernel.call("remove_source", { name = name }) + if rr == nil or rr.ok ~= true then local l = plugin.state.log local last = type(l) == "table" and l[1] and l[1].msg or "" -- 只在**上一次不是同一条**时记,避免每次同步都刷一条 if not tostring(last):find("撤源(重建)失败", 1, true) then logEvent("撤源(重建)失败 " .. tostring(name) .. ": " - .. tostring(rr and (rr.error or rr.err) or "无返回")) + .. tostring(rerr or "(无错误信息)")) end end local src = { @@ -3713,12 +3713,15 @@ end -- 故这里把失败**记进事件日志**,让它在面板上可见,而不是只存在于一个被丢弃的返回值里。 local function dropAccountSource(provider, accountId) local name = accountSourceName(provider, accountId) - local r = __llmsproxy_kernel.call("remove_source", { name = name }) - local ok = r and r.ok - if not ok then - local err = (r and (r.error or r.err)) or "无返回" - logEvent("撤源失败 " .. tostring(name) .. ": " .. tostring(err) - .. "(若提示 not granted,需给 channels 插件授予 remove_source 权限)") + -- ★ 内核桥是 `call(name, args) -> (result, nil) | (nil, err)`: + -- 失败时**第一个返回值是 nil**,原因在**第二个返回值**里。 + -- 我第一版写成 `local r = call(...)` 再读 `r.ok` ⇒ 恒 nil ⇒ 日志只说"无返回", + -- 把真正原因(not granted / 超时 / 拒删最后一个源)丢掉 —— 一句不可操作的 + -- 诊断比没有更糟。两个返回值都要接。 + local r, err = __llmsproxy_kernel.call("remove_source", { name = name }) + if r == nil or r.ok ~= true then + logEvent("撤源失败 " .. tostring(name) .. ": " .. tostring(err or "(无错误信息)") + .. " | 若为 not granted,需给 channels 插件授予 remove_source(声明在 plugin.kernel)") return false, err end return true