Skip to content

Releases: collegeming/cpa-jethub-plugins

v0.11.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 15:47

Full Changelog: v0.10.0...v0.11.0

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 13:11

Full Changelog: v0.9.0...v0.10.0

v0.9.0 — 静态表不是目录

Choose a tag to compare

@collegeming collegeming released this 02 Oct 14:47

修复

1. cline-free/gemini-3.8-flash 调用必失败(HTTP 502)

上游已结束该模型的免费推广(实测 2026-10-02):

检查项 结果
recommended-models 的 free 数组 4 条,不含 gemini
GET /api/v1/models(464 条) cline-free/gemini-3.8-flash 零命中
直连 chat/completions 404 {"error":"model not found"}
CPA /v1/models 仍发布 Gemini-3.8-Flash ← 故障

插件的静态回退表(元数据快照)被当成了目录使用。现在静态条目只有在仍被某个在线来源背书时才发布:

  • 免费家族以 recommended-models 为唯一权威(/api/v1/models 永远不含 cline-free/*);
  • 该端点必须真的返回内容才算权威;任一来源不可用时整表照旧发布(列表为空比列表略旧更糟);
  • 被撤下的条目不再发布并记 warn。

上游恢复推广时会自动恢复发布,静态表的 65536 输出上限一并生效,无需改代码。

2. 日志字段白名单导致告警失效

CPA 控制台格式化器只打印 logFieldOrder 白名单内的字段(v8.0.4),自定义 key 不报错、直接消失。{"models": ...} 落盘后只剩 provider=cline,模型名丢失;v0.8.0 引入的 codearts 剥图告警里 images 计数同样从未显示过。两者改为拼进 message:

[warn] cline 静态目录表条目已下线,不再发布:cline-free/gemini-3.8-flash provider=cline
[warn] CodeArts 剥离了请求中的图片(模型为纯文本),共 4 处 model=deepseek-v4.1-flash

3. 发布流水线:五平台产物首次全部构建成功

此前每一次 tag 推送都失败,release 里始终只有 linux/amd64。三个独立原因:

现象 根因
darwin 任务首行退出 macOS 用 bash 3.2,declare -A 报 invalid option 直接终止
darwin/amd64 排队 24h 未跑 macos-13/macos-14 已退役,改用 macos-15-intel/macos-15
windows 15/15 链接失败 Go < 1.27 把输出名不加引号写进 .def,GNU ld 把 0.1.0 当浮点数解析

最后一项的触发条件是点分版本号,不是横杠(LIBRARY a-b-c.dll 正常,x0.1.dll 失败)。改法:Windows 先链接到不含点的 <id>.dll,再改名为 <id>-v<version>.dll;CPA 按文件名推导插件 id,与 .def 内的 LIBRARY 名无关。

本次 release 首次包含全部 5 平台 × 15 插件 = 75 个 zip(此前仅 15 个 linux/amd64)。

验证

  • 发布产物部署后 /v1/models 不再含 Gemini-3.8-Flash,调用返回 400 model_not_found(而非 502)
  • MiMo-V2.6-Flash 等仍在线的免费模型正常 200
  • 带图请求全部 200,not multimodal 计数保持 0,剥图告警正确显示数量
  • cline 新增 3 个回归测试并做反向验证(禁用背书判断后立刻转红)
  • 本地用 CI 同款 go1.26.0 构建 windows/amd64 15/15 成功;linux 回归 15/15
  • CI 运行 37026777370 五个构建任务 + publish 全绿

部署提示

config.yaml 里指向该模型的 oauth-model-alias 条目需一并删除(文档 §3.4 已更新)。若上游恢复推广,再加回即可。

v0.8.0 — codearts 图片降级,不再整单 406

Choose a tag to compare

@collegeming collegeming released this 01 Oct 05:50

修复:codearts 不再因为图片整单失败

CodeArts 的模型都是纯文本,收到任何带图片的请求会整单拒绝:

InferHub.001001020.406: The request model is not multimodal

拒绝的粒度是整条请求,不是最后一条消息。 实测(每形态 12 次):

请求形态 200 codearts 406
纯文本 12 0
图片在最新一条 12 6
图片只在历史里 12 5

第三行是这类报错最难排查的地方:最新一条是纯文本,表面上没有任何东西提示"有图片"。

改成什么

图片 part 在发往上游之前被换成文本占位符,并记一条 warn 日志:

[image omitted: this CodeArts model accepts text only]

为什么是降级而不是拒绝:DeepSeek-V4.1-Flash 是同名池化模型,四个上游发布同一个名字,只有部分能读图(实测同一张纯蓝图片,sensenova-max 答 Blue,codearts 报 406)。拒绝会让整个名字被一张图打挂;降级则让该上游诚实地说"看不到图",同时其它渠道照常给出完整答案。

用 400 拒绝是错的:CPA 会把 400 判为请求方错误并中断跨渠道故障转移,用户什么都拿不到。

实测效果

修复前后各跑一轮 A/B/C(每个形态 12 次):

406 次数
修复前 5–6 / 12
修复后 0 / 12

同一次带图请求命中 codearts 时答 Unknown(诚实),命中其它渠道时答 Blue(正确)。

顺带查清了两个 CPA 行为(v8.0.4 源码 + 实测)

  • 冷却是按「凭据+模型」,不是按渠道整体。 同一账号下模型 A 被限流不影响模型 B(实测 cline 上 DeepSeek 429 时,同凭据的 Nemotron 仍 200)。
  • 冷却时长是固定阶梯 1s → 2s → 4s → … 30min,上游回复里的 Try again in 14h 53m 到不了 CPA:核心路径不解析 body 文案,且插件 ABI 的错误对象只有 code/message/retryable/http_status 四个字段,没有时长字段,auth.save 写回的 next_retry_after 也会被宿主覆盖。因此不存在"针对某渠道模型设置冷却时长"的配置项——粒度已经是按渠道模型,缺的是时长而时长不可配。唯一可配的是按凭据整体关闭冷却(disable_cooling: true)。

详见 docs/DEPLOYMENT.md §3.7(同名池化与模态能力)与 §3.8(上游限流与冷却)。

测试

新增 plugins/codearts/vision_test.go,7 个用例覆盖:最新消息带图、仅历史带图、三种图片 part 拼写、工具结果内嵌图片、无图请求逐字不变、占位符是 text part。做了反向验证:停用剥离调用后 5 个用例立刻转红。

go build / go vet / gofmt / 全部包测试均通过。

v0.7.0 — ZCode 不再提供签到(与 cline 一致)

Choose a tag to compare

@collegeming collegeming released this 01 Oct 03:11

ZCode 的领取端点强制要求阿里云验证码,插件无法满足,所以它此前提供了一个每天必然失败一次的动作——长期占用 HUB 的 failed 计数,而那个计数是留给真正意外的。人工验证通道也做过了,失败在最后一步:验证码参数是公开的(服务端在 client/configs 里公布 sceneId/prefix/region),请求头契约在官方客户端 bundle 里,页面确实加载了阿里云 SDK 并成功初始化——但组件渲染不出验证(embed/popup、传选择器/传元素都试过,控制台无报错)。最可能的原因是该验证码场景未授权本页面来源。

于是采取 cline 的立场:完全不提供签到。

删除而不是留成不可达:/checkin 资源路由、签到页、checkinJSON 及其状态词helper、整条领取链路(claimDaily/claimPlan/claimFailureText/活跃上报/它依赖的 preview)、以及验证码机制(captcha.go、组件、脚本上下文转义)——测试一并移除。

保留(仍然可用且有用):推理、token 余额与额度桶、凭据有效期、模型目录、登录流程。

两个契约点,都做了反向验证:

  • 资源路由测试现在断言不存在签到路由(与 cline 插件同一个不变量),路由无法悄悄回来;
  • HUB 清单标记 supportNone 并写明原因。

实测:/checkin → 404;一键签到把它报成「不支持」(与 cline 并列),failed 计数为 0;GLM-5.3-Flash 推理仍返回 OK。

开发清单里也补了这条原则:注定失败的动作不要提供入口,相关代码要删掉而不是留着看起来只是没接好。

v0.6.1 — ZCode 人工验证通道(已实现,当前不可用)+ 模型数补齐

Choose a tag to compare

@collegeming collegeming released this 01 Oct 02:54

ZCode 验证码:人工验证通道做出来了,但渲染不出来

领取端点的验证码是 ZCode 每日额度唯一的拦路石。要试它的三块拼图其实都是公开的:

  • 参数由服务端公布,不在闭源客户端里:GET /api/v1/client/configs?platform=unknown → {"enabled":true,"prefix":"no8xfe","region":"cn","sceneId":"11xygtvd"}
  • 请求头契约在你本机已装的客户端里(~/.zcode/server/zcode-server.cjs):X-Aliyun-Captcha-Verify-Param + 可选 X-Aliyun-Captcha-Verify-Region
  • 阿里云前端 SDK 是公开脚本,正是吃这三个值

所以插件现在会:读取配置;遇到 3007 且没有令牌时渲染官方验证码组件;通过查询串收回令牌(资源路由只派发 GET)并带着两个头重试——请求头按字面名做了单元测试。

但它不工作,页面也如实这么说。 实测(面板来源):SDK 加载成功、initAliyunCaptcha 执行无异常、getInstance 回调触发、控制台干净——而元素在 embed/popup、传选择器/传元素等各种组合下始终为空。最可能的原因是验证码场景未授权本页面来源(阿里云侧配置,属 ZCode 所有)。转不完的圈比原来那句话更糟,所以组件 6 秒后主动放弃、点名回退方案并隐藏提交按钮。

写这条降级断言时查出一个真实注入:场景参数来自服务端文档,而 strconv.Quote 不足以让一个值安全地嵌进 <script>——HTML 解析器在字符串中间遇到 </script 照样结束元素。jsStringLiteral 现在转义 <、>、& 与 JS 行分隔符,并有测试拿恶意 scene id 打它。

模型数补齐

codearts / lobsterai / trae 三个渠道此前不发布 model_count,HUB 那行因此没有「模型 N」。现在:codearts 8、lobsterai 30、trae 28(cline 本来就有)。

注意这些数字是插件自己的目录,在宿主 oauth-excluded-models 过滤之前——lobsterai 报 30 而 /v1/models 只列 7,是排除清单在起作用,不是 bug。

每一项断言都做了反向验证:删掉验证码头、永不渲染组件、发送空的 region 头(缺失与空值是不同的请求)、去掉脚本上下文转义。

v0.6.0 — 统一模型命名 + 新增渠道开发清单

Choose a tag to compare

@collegeming collegeming released this 01 Oct 02:33

模型命名统一

atomcode 与 codearts 此前发布的是上游自己的 id(glm5.3-flash、qwen3.8-27b、deepseek-flash、deepseek-v4.1-flash),与其它渠道已有的名称并存,同一个模型出现两个条目。现在统一发布 GLM-5.3-Flash、Qwen3.8-27B、DeepSeek-V4.1-Flash,并做双向映射,网关收到的仍是它自己的 id。

改名放在插件里而不是 oauth-model-alias,这是实测结论:同一个别名目标被多个 provider 映射时,胜出方在多次重载之间会变——atomcode 的 qwen3.8-27b 曾被留在 cline 的 Qwen3.8-27B 旁边,同一模型两个条目;而映射到一个全新名字每次都生效。插件自己发布的名字会与其它渠道的同名模型合并(这正是 zcode 一直依赖的行为)。别名表保留它真正的用途:引入一个全新名字。

反向映射是承重的,也很容易忘:对外发布 Qwen3.8-27B 却把它发给上游,网关会用「参数错误」哨兵回应而不是报错。两个方向都有测试,且都通过删除反向查表做了反向验证。

新增渠道开发清单

新增 docs/ADDING-A-CHANNEL.md——本次会话缺的就是它。覆盖插件之外那些看不见的步骤:三个登录入口、统一命名、hub 清单条目及其必需的 action=claim、hub 真正会渲染的状态 JSON 字段、签到响应必须携带的顶层 message、写闸门、排除/别名的作用顺序、发布接线,以及每条断言的反向验证。

最后附「模型不见了」的排查顺序——从宿主的排除清单查起,而不是从上游反推。这个错误在本次会话里犯过两次。

v0.5.4 — 一键签到:能领的领掉,领不了的说明原因

Choose a tag to compare

@collegeming collegeming released this 01 Oct 02:08

一张截图里的三个问题。

ZCode 为什么失败

claim 是官方客户端唯一还挂阿里云验证码的端点,而且服务端是强制的:不带令牌一律 400 {"code":3007,"msg":"captcha verify failed"},响应里没有可解的挑战。本插件不产出验证码,所以 ZCode 的一键签到不可能成功,重试没有意义。推理不受影响(实测无需验证码)。

顺带纠正:我此前写的「领取端点目前也不需要验证码」是从 skip_model_request: true 过度外推的——那个字段说的是模型请求。

而且失败原因根本没送到你眼前:HUB 的签到行只读顶层 message,而 ZCode 的响应没有这个字段,于是那句可执行的话躺在 outcomes[].message 里没人看,页面上只剩一个 failed。现在 ZCode 会发布摘要,措辞也直接说明「重试不会有不同结果」以及该去哪里领。

Raccoon 为什么不能一键

它真的没有每日签到(每日 300 由服务端自动发放,没有端点)。但一次性桌面端登录奖励是可以领的,而且你账上正躺着 3000 分没领——之前那句「请在插件页单独领取」等于让你绕路。

现在一键动作会领它,两道闸保证放在每天按的按钮后面是安全的:

  1. 先读奖励状态(由账单历史推导),已领过就报「已领取」,一次写请求都不发;
  2. 服务端 granted 标志兜底:重复调用返回 granted:false,映射为「已领取」而非第二次「领取成功」。

真实账号实测:276 → 3276(reward 桶 0 → 3000);再次运行报「已领取」,余额不变。

其它

  • 该渠道的路由契约测试原本断言「不允许存在 /checkin」。现在断言的是相反的不变量:路由存在,且描述必须写明本渠道没有每日签到,以免下一个读者误解。
  • 传了不存在的 auth_index 时,原本回「没有可用账号」,会让拿着过期索引的人去找一个明明就在的凭据。现在会指出是哪个选择器没匹配上。

每一项新断言都通过破坏它所保护的行为做了反向验证:页面加载就写入、忽略已领取状态、丢掉顶层 message、让成功压过失败。

v0.5.3 — AtomCode 支持补充服务端目录已撤下的模型

Choose a tag to compare

@collegeming collegeming released this 01 Oct 01:36

新增配置项 extra_models:把网关能调用、但服务端 models-v2 目录已不下发的模型 id 加到实时目录之上。

为什么需要它

网关和权益目录确实不一致。2026-10-01 在同一个 CodingPlan Lite 账号上实测(用本插件自己的身份):

模型 id 结果 在 models-v2 里
deepseek-flash 200,正常内容 否
Qwen/Qwen3-32B 200,正常内容 否
Qwen/Qwen2-VL-72B 200,正常内容 否
Qwen/Qwen3-4B-Instruct-2507 200,但内容是「三方请求失败: 502 …」 否
no-such-model-xyz 200,但内容是「参数错误」 否

所以:「能调用」不等于「已下发」,更不等于「可用」——上表里就有一个返回 200 却在网关内部失败的。这也是它做成配置项而不是内置列表的原因:只有持有账号的人能判断某个未下发模型值不值得暴露;插件不该替用户猜。插件只对抓到过服务端原始元数据的 id 附带窗口/思考级别,其余一律不带任何声明(猜出来的上下文窗口会被客户端当真)。

用法

atomcode:
  extra_models:
    - deepseek-flash

三种写法都接受:单个字符串、逗号分隔、YAML 列表。补充模型加在实时目录之上(不是替代),去重;在模型列表和状态页的「可用模型」卡片里都标注为「补充模型」,与套餐权益区分开。

顺带修复

多识别一种静默失败:上游故障被当成模型回答返回(HTTP 200 + 正文「三方请求失败: 502 …」)。此前它会被原样当成模型的回答——在 agent 循环里更会成为模型的下一轮输入。现在会转成可重试的上游错误。

新增测试:合并接线、三种配置写法、未知 id 不得凭空声明元数据、新的失败形态;每一项都做了反向验证。

v0.5.2 — 修复到期时间格式导致的续期静默失效

Choose a tag to compare

@collegeming collegeming released this 30 Sep 18:57

修复一个静默故障:CPA 会把 auth 记录里的 expires_at 规范化成 RFC3339 存回(插件写毫秒数字串,落盘变成 2026-09-30T17:48:18Z)。MiniMax 的到期解析只接受纯数字,读不懂就按「没有到期时间」处理,而该渠道把「没有到期时间」定义为「未过期」——于是凭据看起来永远健康,续期一次也没跑,直到上游返回 401。它的令牌只有 3600 秒,所以一小时内就会暴露。

修复范围:minimax、loomy、raccoon 现在同时接受数字(毫秒/秒)与 RFC3339。loomy 原本连 JWT 回退都没有,会以完全相同的方式静默失败;raccoon 的回退只覆盖令牌恰好是 JWT 的情况。codearts / trae / codebuddy / lobsterai 原本就接受多种写法。

续期现在是被证明的,而不是假设的,对外公布的断言也同步更新:把凭据改到距到期 120 秒(落在 300 秒续期窗口内)后发一次推理,请求返回 200 且落盘的 access_token 变成了新的——续期在该请求之前跑完了;随后在窗口之外再发一次,令牌不再轮换,说明续期是按需触发而非每请求一次。由于该断言此前是有意置为 false 的,守着它的测试现在要求证据必须写在代码里,不能再无理由翻回去。

三个插件都补了用真实落盘值做输入的测试,并各自做了反向验证(打断 RFC3339 分支即变红)。