@ -344,7 +344,13 @@ local PLATFORMS = {
} ,
hosts = { " api.workos.com " , " api.cline.bot " , " app.cline.bot " } ,
-- cline 的 chat 路径是 /api/v1/chat/completions( 参考 CLINE_CHAT_PATH) 。
base_url = " https://api.cline.bot/api/v1/chat/completions " ,
base_url = " https://api.cline.bot " ,
-- ★ 路径必须在 endpoint 里,**不能**塞进 base_url:
-- 内核的 URL 是 `base_url + endpoint`( provider.go ChatURL) ,
-- 而适配器默认 endpoint 是 "/chat/completions" ⇒ 若 base_url 已含
-- 完整路径,实际请求就变成 .../api/v1/chat/completions/chat/completions ⇒ 上游
-- 回 `{"error_msg":"404 Route Not Found"}`( APISIX 的措辞)。
endpoint = " /api/v1/chat/completions " ,
-- 远端模型目录(照参考 cline-models.ts: **必须同时打两个端点**)。
-- 关键:/api/v1/models 的 460 个 id 里**没有** cline-free/*,免费模型只由
-- recommended-models 下发;只打前者会看不到任何免费模型。
@ -414,7 +420,13 @@ local PLATFORMS = {
} ,
hosts = { " copilot.tencent.com " , " www.codebuddy.cn " } ,
-- buddy 的 chat 端点含 /v2 前缀(参考 CHAT_API_BASE = .../v2 + /chat/completions) 。
base_url = " https://copilot.tencent.com/v2/chat/completions " ,
base_url = " https://copilot.tencent.com " ,
-- ★ 路径必须在 endpoint 里,**不能**塞进 base_url:
-- 内核的 URL 是 `base_url + endpoint`( provider.go ChatURL) ,
-- 而适配器默认 endpoint 是 "/chat/completions" ⇒ 若 base_url 已含
-- 完整路径,实际请求就变成 .../v2/chat/completions/chat/completions ⇒ 上游
-- 回 `{"error_msg":"404 Route Not Found"}`( APISIX 的措辞)。
endpoint = " /v2/chat/completions " ,
-- 远端模型目录(照参考 buddy.ts CONFIG_PATH + buddy-oauth.ts fetchModels) 。
-- 关键:必须带 product 身份头,否则 WorkBuddy 会以 CodeBuddy 身份请求。
models_remote = {
@ -688,7 +700,13 @@ local PLATFORMS = {
fallback = " 2026.9.4 " ,
} ,
-- lobsterai 的 chat 路径是 /api/proxy/v1/chat/completions( 参考 LOBSTERAI_CHAT_PATH) 。
base_url = " https://lobsterai-server.youdao.com/api/proxy/v1/chat/completions " ,
base_url = " https://lobsterai-server.youdao.com " ,
-- ★ 路径必须在 endpoint 里,**不能**塞进 base_url:
-- 内核的 URL 是 `base_url + endpoint`( provider.go ChatURL) ,
-- 而适配器默认 endpoint 是 "/chat/completions" ⇒ 若 base_url 已含
-- 完整路径,实际请求就变成 .../api/proxy/v1/chat/completions/chat/completions ⇒ 上游
-- 回 `{"error_msg":"404 Route Not Found"}`( APISIX 的措辞)。
endpoint = " /api/proxy/v1/chat/completions " ,
-- 远端模型目录(照参考 lobsterai.ts LOBSTERAI_MODELS_PATH)
models_remote = {
-- 参考真值 LOBSTERAI_API_BASE( lobsterai-server.youdao.com) 。
@ -727,7 +745,17 @@ local PLATFORMS = {
vendor = " opencode " ,
flow = " paste " ,
-- opencode 的 chat 路径是 /v1/chat/completions( 参考 chatPath) 。
base_url = " https://opencode.ai/zen/v1/chat/completions " ,
-- ★ base_url 必须保留 `/zen` 段:参考 opencode-product.ts:56 的
-- `baseUrl: 'https://opencode.ai/zen'` + chatPath `/v1/chat/completions`。
-- 实测(无凭据):
-- https://opencode.ai/zen/v1/chat/completions → 500( 路由存在, 鉴权前先炸)
-- https://opencode.ai/v1/chat/completions → 404 + HTML( 网页)
base_url = " https://opencode.ai/zen " ,
-- ★ 路径必须在 endpoint 里,**不能**塞进 base_url: 内核的 URL 是
-- `base_url + endpoint`( provider.go ChatURL) , 而适配器默认 endpoint 是
-- "/chat/completions" ⇒ 若 base_url 已含完整路径,实际请求就变成
-- .../v1/chat/completions/chat/completions ⇒ 404 Route Not Found。
endpoint = " /v1/chat/completions " ,
-- 远端模型目录(照参考 opencode-product.ts modelsPath)
models_remote = {
endpoints = { { url = " https://opencode.ai/v1/models " , method = " GET " } } ,
@ -853,7 +881,13 @@ local PLATFORMS = {
interval = 2 ,
} ,
-- qoder 的 chat 路径是 /model/v1/chat/completions( 参考 QODER_CHAT_PATH) 。
base_url = " https://api2-v2.qoder.sh/model/v1/chat/completions " ,
base_url = " https://api2-v2.qoder.sh " ,
-- ★ 路径必须在 endpoint 里,**不能**塞进 base_url:
-- 内核的 URL 是 `base_url + endpoint`( provider.go ChatURL) ,
-- 而适配器默认 endpoint 是 "/chat/completions" ⇒ 若 base_url 已含
-- 完整路径,实际请求就变成 .../model/v1/chat/completions/chat/completions ⇒ 上游
-- 回 `{"error_msg":"404 Route Not Found"}`( APISIX 的措辞)。
endpoint = " /model/v1/chat/completions " ,
-- Qoder 的错误信封是**双层编码**的,且 10605(排队) 与 110(额度耗尽)
-- 语义相反 —— 通用 openai 适配器只能看到外层,产出用户看不懂的原因串。
-- 故用本插件自装的 channels-qoder( 厂商码留在插件域, 内核零厂商名) 。
@ -1007,9 +1041,24 @@ local PLATFORMS = {
access_key_secret = " zsak6eadrbawz683wf5r3m2snrwj868r " ,
app_id = " GM3LOOMY " ,
} ,
-- loomy 的 chat 路径 是 {apiBase}/chat/completions( 参考 loomy-adapter.ts:494
-- 实测标准 OpenAI 兼容)。
base_url = " https:// loomy.xunfei.cn/chat/completions " ,
-- loomy 的 chat 端 是 {apiBase}/chat/completions( 参考 loomy-adapter.ts:494)。
--
-- ★ host 是 ** loomyad .xunfei.cn/api/v1**(参考 LOOMY_API_BASE) , 不是
-- `loomy.xunfei.cn` —— 后者是 **Web 前端/OAuth 回调**域(本块的
-- wechat.redirect_uri 正用它)。实测:
-- POST https://loomy.xunfei.cn/chat/completions
-- → 200 + `<!DOCTYPE html>`(网页!根本不是 API)
-- POST https://loomyad.xunfei.cn/api/v1/chat/completions
-- → 200 + `{"code":"100002","desc":"缺少 token"}`(正常 JSON)
-- 写成前端域时,无论路径怎么拼都不可能是 API。
--
-- ★ 路径必须在 endpoint 里,**不能**塞进 base_url: 内核的 URL 是
-- `base_url + endpoint`( provider.go ChatURL) , 而适配器默认 endpoint 是
-- "/chat/completions" ⇒ 若 base_url 已含完整路径,实际请求就变成
-- .../chat/completions/chat/completions ⇒ 上游回
-- `{"error_msg":"404 Route Not Found"}`( APISIX 的措辞)。
base_url = " https://loomyad.xunfei.cn/api/v1 " ,
endpoint = " /chat/completions " ,
adapter = " openai " ,
-- 兜底目录(照参考 LOOMY_FALLBACK_MODELS) 。此前 "loomy-default" 是我编的。
models = {
@ -1044,7 +1093,13 @@ local PLATFORMS = {
} ,
-- 推理是标准 OpenAI 兼容(实测 POST /api/web/llm/v2/chat/completions)
-- raccoon 的 chat 端点是 /api/web/llm/v2/chat/completions。
base_url = " https://xiaohuanxiong.com/api/web/llm/v2/chat/completions " ,
base_url = " https://xiaohuanxiong.com " ,
-- ★ 路径必须在 endpoint 里,**不能**塞进 base_url:
-- 内核的 URL 是 `base_url + endpoint`( provider.go ChatURL) ,
-- 而适配器默认 endpoint 是 "/chat/completions" ⇒ 若 base_url 已含
-- 完整路径,实际请求就变成 .../api/web/llm/v2/chat/completions/chat/completions ⇒ 上游
-- 回 `{"error_msg":"404 Route Not Found"}`( APISIX 的措辞)。
endpoint = " /api/web/llm/v2/chat/completions " ,
adapter = " openai " ,
-- 兜底目录(照参考 RACCOON_FALLBACK_MODELS) 。此前 "raccoon-default" 是我编的。
-- 注意 sn- 前缀是本平台的真实命名约定( sensenova 系列)。
@ -3654,14 +3709,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 +3768,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
@ -11114,7 +11172,11 @@ function plugin.__inject_refresh_platform_probe(args)
label = id ,
flow = " manual " ,
adapter = " openai " ,
base_url = " http://127.0.0.1:1/v1/chat/completions " ,
base_url = " http://127.0.0.1:1/v1 " ,
-- 照正式平台同样的分工: base_url 只到路径前缀,路径放 endpoint
-- (内核 URL = base_url + endpoint) 。测试夹具也照此写,
-- 免得将来有人把这行当范例复制进正式平台。
endpoint = " /chat/completions " ,
refresh = { style = tostring ( args.style or " google " ) , url = tostring ( args.refresh_url or " " ) } ,
models = { " m1 " } ,
hosts = { " 127.0.0.1 " } ,