跳到主要内容
返回项目档案
独立作品进行中

Magpie Plus · 多模型网关与看板

从一块余额看板出发,自研三套平台网关,最后二开 magpie 并把看板并回网关

角色
设计与实现(单人)
量级
四代演进 · 三套平台网关 · 一条到期优先路由
时间
2026年10月 — 至今
GoTypeScriptNode.jsSQLiteWailsOpenAI 协议Anthropic 协议Responses APISSEChrome DevTools Protocol

做了什么

  • 起点是一块看板:power-meter 用批次级 CreditLot 与到期时间线,把 9 个平台的额度压成一张按「最快作废」排序的表
  • 中间自研三套平台网关(WorkBuddy / Qoder / Trae),把客户端内积分转成 OpenAI / Anthropic / Responses 三协议端点,带账号池、分级冷却与 doctor 自检
  • 二开 magpie(Go)为 magpie plus:独立 bundle id 与登录项、可与官版共存;power-meter 以 sidecar + 反向代理并入 GUI,成为「余额看板」页
  • 新增 routing=expiry:用看板的批次到期时间排序账号,并为 Qoder / Trae / CodeArts 写薄包装插件补上 runsOutAt
  • 跟上上游 225 个提交只解 7 处冲突——二开代码集中在新包与薄包装,不碰上游核心

起点:一块看板

手上同时用着几个平台的模型额度,每个平台又有多个账号:有的按月订阅、有的每日签到、有的分批到账、分批作废。 余额散在各家的网页控制台里,哪个账号先用、什么时候作废,只能一个个打开看。

最初的版本只想解决这件事——把余额放在一页里看:

  • 数据契约先定:ProviderSnapshot / QuotaWindow(session / daily / weekly / billing)/ CreditLot(带到期时间的积分批次)/ DailyUsage,以及 8 种状态(正常、限流、凭证失效、上游异常…)。
  • 批次是核心:余额不是一个数字,而是「一堆会过期的东西」。CreditLot 记剩余量、发放量、到期时间,看板按最快到期排序高亮。
  • 9 个平台适配器:Qoder(双站点)、Trae、CodeBuddy、CodeArts(AK/SK 与 Cookie 双模式)、多 key 合并卡片、签到积分平台等,各自把异构接口压进同一份契约。
  • 凭证自己抓:.env + accounts.json 热加载;Chrome DevTools Protocol 抓 Cookie,扫码/链接登录后自动落库。
  • 前端是独立静态页:总览 / 按平台 / 额度卡片 / 到期时间线 / 诊断,命令面板(⌘K),无构建步骤;后端零运行时依赖。

这个阶段最重要的结论是:余额的价值不在数字,在「什么时候失效」。先过期不先用,额度就是白扔。

第二步:三套平台网关

看板能看,但额度只能在厂商自己的客户端里花。要让 Claude Code、Codex、Cline、Cursor 都能用上,得给每个平台写一层协议网关。

WorkBuddy(腾讯 CodeBuddy / WorkBuddy,国内版 + 国际版):复用桌面端登录态,不必单独登录;把会话、设备指纹、每日活跃都留在网关侧;向上暴露 OpenAI / Anthropic 兼容端点,账号池轮转、熔断冷却、会话粘性,另有定时签到与保活。

Qoder:它有两套平面——业务接口走 Bearer,推理接口走自研的 COSY 签名。网关把短期登录态和请求级签名都藏在内部,对上层签发一把静态 sk-,客户端只知道 base_url + key。

Trae:一个进程同时提供 Anthropic Messages、OpenAI Chat Completions 与 Responses 三套端点;多账号按剩余积分挑号,限流 / 鉴权失效 / 上游异常分级冷却;doctor 逐项自检,挑号失败时列出每个账号被跳过的原因;模型名差异用别名一次映射。

三套网关解决的是同一类问题:

通用 API 的假设 平台实际情况 网关的处理
长期静态 sk- 密钥 短期登录态,JWT 会换 网关签发密钥,内部映射账号池
Authorization: Bearer 单头 请求级签名 / 自研协议 各 provider 内部实现签名,对上层透明
不过期 积分有到期时间、倍率、连登档位 独立的签到调度与到期视图
无风控 设备指纹、节奏、并发被校验 稳定设备号 + 每日抖动 + 串行签到

三套网关之后又合并出 credit2api:WorkBuddy / Trae / Qoder / CodeArts 四个平台收敛成一个入口,签发统一的密钥,签到、账号池与用量审计放在一处——否则三套配置、三套账号、三套签到,维护成本会反噬收益。

第三步:二开 magpie → magpie plus

到这一步,网关、协议、账号池都有了,缺的是「常驻的载体」:一个菜单栏应用、一套 GUI、能把各家 Agent 的配置改对、能在多个 provider 之间切换。这些从零写不值得——magpie 已经做了,而且 MIT 许可允许独立分发。

于是决定二开。难点在于 magpie 是 Go(70+ 个 internal 包),power-meter 是 TypeScript/Node,不能代码级合并,只能做进程级集成:

magpie plus (Go, 127.0.0.1:3425)
  GUI 新页面 plugins/powermeter/  ──fetch──▶ /api/powermeter/*
        │                                        │
        │                          internal/powermeterproxy(反向代理)
        │                                        │
        │                          internal/powermeterproc(拉起 / 守护)
        ▼                                        ▼
  余额卡片 / 到期时间线 / 账号 / 诊断      power-meter (Node sidecar, 随机回环端口)
                                          /api/summary · accounts.json · .env
  • 不改 power-meter:9 个适配器、聚合层、到期时间线原样复用,它是独立仓库,继续独立演进。
  • sidecar 化只要三个开关:端口、账号文件路径、.env 路径都可配,于是不用改一行源码。
  • 安全默认:sidecar 只绑回环,每次运行换一个 token,配置放在 magpie 自己的配置目录下;余额看板默认关闭。
  • 身份分离:com.a1ether.magpie-plus、magpie plus 的 bundle 名与登录项,官版 magpie 与 plus 能同时装、同时开;配置目录故意共用(账号与用量历史只登录一次),网关端口先到先得。
  • 跟上游:fork 的代码集中在新包与页面插件,不碰核心;合入上游 225 个提交只解了 7 处冲突。

第四步:到期优先路由

magpie 原生有 smart 路由,按剩余额度挑账号。但它的视野里没有「批次到期」这回事:Qoder 的积分藏在网页 Cookie 接口里、CodeArts 是一本逐笔台账、Trae 是签到攒下来的——社区插件只报汇总,smart 对这些账号就退化成按列表顺序。

于是补了两层:

路由层:新增 routing=expiry(routes.ExpiryFirst)。它读 sidecar 的 /api/summary 到期时间线(30 秒缓存,从不阻塞请求),把平台与账号名映射到 magpie 的账号上,按「最早作废」排序;读不到就退回 smart 的顺序,额度接近耗尽的账号排最后。GUI 的 provider 编辑与路由组菜单、Routing 页说明、CLI(routing=expiry)、TUI 与四种语言都补齐。

数据层:给三个平台写薄包装插件(magpie-qoder-cookie / magpie-trae-batches / magpie-codearts-batches),只重写插件的 auth.usage,把每个额度桶里最早到期的批次写成 runsOutAt / runsOut。magpie 原生 smart 立刻就能用上——不装补丁也能跑,只是没有到期时间。

几个关键判断

  • 复用优于重写:9 个适配器约 8K 行 TS,含 CDP 抓凭证、AK/SK、签到积分、双站点回退,重写成 Go 的成本远高于维护一个 sidecar。
  • 数据只有一份:看板与路由读同一个 /api/summary,不各算一套「哪个先到期」。
  • 可解释:为什么这个请求走了那个账号、为什么这个账号被跳过,doctor 与 trace 都要能说出来。
  • 不碰上游核心:新增包 + 薄包装,是能持续跟上游的前提。
  • 默认安全:只绑回环、每次换 token、默认关闭——本地工具也不该默默监听到公网。

结果

现在所有客户端指向同一个本地入口,所有账号的余额与到期时间在一页里,额度按「最快作废」自动消耗。这条线从一块看板开始,最后长成了一个「网关 + 看板 + 路由」的闭环——每一层都不是新造的数据,而是同一份余额的三种用法。

还在继续

跟随上游更新、补更多平台的批次到期、把看板的诊断信息接进网关的请求 trace。