dsh-gemini-quota
v0.3.2
Published
在 DeepSeek Harness 输入框显示 Gemini 额度条,点开即多号池面板:逐号剩余额度、启停冷却、检测保活、一键切号
Maintainers
Readme
dsh-gemini-quota
在 DeepSeek Harness 输入框那一行显示一条 Gemini 额度小条,点一下弹出多号池面板。

- 只在当前选中的模型属于 Gemini 时出现,切到 DeepSeek / Codex 自动消失;
- 鼠标悬停显示剩余量与重置时间(含账号),提示气泡跟随 DSH 主题配色(明暗主题与皮肤插件都会同步);
- 0.2.0 新增账号池面板:点一下额度条,逐个账号看 5h / 7d 剩余额度,并能直接 启用 / 停用(冷却)/ 检测登录态 / 保活 / 切号——不用切去反代后台网页;
- 0.3.0 新增降级守卫:额度耗尽时 Gemini 会静默换成更弱的模型却仍返回 200, 额度条会染成警告色 + ⚠️,写明「请求 X,实际 Y」,并给一键换号;
- 0.3.1 修复额度条与账号不同步:多号池 + 额度感知选号时请求会在号之间改道, 额度条过去可能一直显示另一个号的额度(数字看着挺正常,所以很隐蔽)。现在它跟 反代调度器的结果一致 —— 也就是下一条请求会用的那个号;在面板里切号 / 启停之后 立刻刷新,不用等下一个轮询周期;
- 数据来自本地
gemini-web2api-go反代的/admin/api/*。
本插件是显示 + 控制层,不含反代本身。你需要先自己跑一个 gemini-web2api-go。
注意:上游 v4.22.0 没有
GET /admin/api/quota这个接口——它是本机对上游的 本地补丁(internal/app/quota.go,上游升级会被覆盖,需备份)。没有它, 额度条永远不显示(路由返回 502),但账号池面板仍然可用(它只依赖上游已有的/admin/api/cookies)。账号池面板里的逐号额度另需一个本地扩展:
GET /admin/api/quota?account_id=N。 没打这个补丁时,面板会明确标出「按号查额度不支持」,不会拿自动选号的数字冒充某个账号。
前置条件
一个在跑的反代,默认地址
http://127.0.0.1:8083;它的 admin token,放在下面任一位置(按优先级):
token配置项(直接写在 config 里,不推荐提交到仓库);- 环境变量
GEMINI_WEB_ADMIN_TOKEN(可用tokenEnv改名); envFile指向的文件里的GEMINI_WEB_ADMIN_TOKEN=...;$DSH_HOME/gemini-web2api.env(默认~/.dsh/gemini-web2api.env)——推荐,机器相关的东西放这里。
install -m 600 /dev/null ~/.dsh/gemini-web2api.env printf 'GEMINI_WEB_ADMIN_TOKEN=%s\n' '<你的 admin token>' > ~/.dsh/gemini-web2api.env
安装
在 DSH 侧边栏 插件 页里安装(输入包名即可):
dsh-gemini-quota也可以走 CLI / 其他 spec 形式:
# 注册表包
dsh plugin --profile <profile> add dsh-gemini-quota
# 本地目录(开发用)
dsh plugin --profile <profile> add /path/to/dsh-gemini-quota
# tarball / git
dsh plugin --profile <profile> add ./dsh-gemini-quota-0.2.0.tgz
dsh plugin --profile <profile> add github:xinglan163/dsh-gemini-quota安装后默认启用。本插件没有任何依赖构建脚本,因此不会触发 pnpm 的 allowBuilds 审批。
配置
改组合包自带的 cordis.patch.yml,或在你 profile 的 cordis.patch.yml 里按 id: gemini-web-quota 覆盖:
| 项 | 默认 | 说明 |
|---|---|---|
| baseUrl | http://127.0.0.1:8083 | 反代地址 |
| providers | ["gemini-web"] | 哪些 DSH provider id 触发显示(决定门控) |
| matchModelPrefix | true | 额外按模型名 gemini-* 兜底 |
| token | — | 直接给 admin token(优先级最高) |
| tokenEnv | GEMINI_WEB_ADMIN_TOKEN | 从哪个环境变量读 token |
| envFile | $DSH_HOME/gemini-web2api.env | 从该文件读 token |
| timeoutMs | 8000 | 上游超时 |
| readOnly | false | true = 面板只读,禁用一切账号动作 |
providers 必须和你在 llm-pi-ai 里给反代起的 provider 名一致(默认 gemini-web)。
账号池面板(0.2.0)
额度条点一下弹出面板(再点 / 点外面 / 按 Esc 关闭):

Gemini 账号池 1/2 启用 [刷新] [反代面板] [✕]
● Pro(FF导入) #1 [当前] 5h ▓▓▓▓ 100% 7d ▓▓▓ 80%
出口 直连 · 15 个 cookie · 上次成功 2 小时前 [停用][检测][保活][切到此号]
● 备用号 #2 5h ░░░░ 0% 7d ▓▓▓ 55%
出口 新加坡 · 失败 3 次 · 上次成功 1 天前 [启用][检测][保活][切到此号]| 元素 | 含义 |
|---|---|
| ● 颜色 | 绿=在用;黄=待检测(还没成功用过);红=鉴权失败中(多半 cookie 过期);灰=已停用 |
| [当前] | 额度条上显示的正是这个号 —— 反代调度器下一个请求会挑的号(所以点完「切到此号」立刻就变) |
| 5h / 7d | 该账号自己的网页端额度(?account_id=N),失败时显示原因,不支持时显示 — |
| 第二行 | 出口代理、失败计数、cookie 个数、上次成功时间(悬停看完整 last_error) |
| 启用 / 停用 | 即"冷却"开关:停用的号不会被调度器选中 |
| 检测 | 真的去上游探一次登录态(/check),结果直接显示在下方 |
| 保活 | 刷新 cookie(/rotate,SAPISID 轮换),返回刷新了哪几个字段 |
| 切到此号 | 需点两次确认:启用目标号,并停用其余已启用的号 |
「切到此号」为什么要点两次:反代的调度器只按 (fail_count, last_used_at) 轮转,
没有「活跃账号」这个开关,所以"让接下来的请求都走这个号"唯一诚实的实现就是
把别的号禁用掉——这是会一次改动多行的动作,值得一次确认。
「反代面板」按钮会新开 baseUrl/admin/(反代自带的 web 面板),加 cookie / 配代理这类
不常做的事还是去那边。
降级守卫(0.3.0)
额度用完后,Gemini 会静默把你的模型换掉,但 HTTP 照样回 200。
你选了 4 Argon(付费号专属)。当账号 5 小时额度见底时,上游不报错,而是把这一轮 转给更笨的 3.5 Flash-Lite 去答,然后正常返回成功。于是 DSH 以为用的是强模型, agent 还会理直气壮地说"我做完了"——issue #41 里管这叫「产生严重幻觉并破坏任务」。
额度条会整条染成警告色并加一个 ⚠️,悬停第一行就是原因:
⚠️ 最近一次请求被降级:请求 gemini-4-argon,实际 3.5 Flash-Lite
5h 额度:剩余 5%
账号:Pro(FF导入)
点一下:账号池面板点开面板,顶部是告警条 + 一个按钮:切到额度最充足的号(两下确认,与行内 「切到此号」同一套逻辑:启用目标号 + 停用其它已启用的号)。
判定规则(以及为什么这么判)
| 情形 | 判定 |
|---|---|
| 请求 gemini-4-argon,上游自报 4 Argon / 4 Argon High | ok |
| 请求 gemini-4-argon,上游自报 3.5 Flash-Lite | downgraded |
| 上游没自报显示名(生图 / 生视频 / 抽取失败) | unknown —— 不亮红灯 |
| 模型不在插件内置表里(例如将来新增) | unknown —— 不亮红灯 |
两个刻意的设计:
- 判不了就说判不了。
unknown绝不等于"没问题"——把"看不见"伪装成"没降级", 比漏报更糟(用户会开始无视这个红灯)。 - 上游改名要容忍。Google 把 3.7 原地升级成 3.8 过(同一个 hex、显示名变了), 所以 id→显示名是一张容错表,遇到改名不误报。
真相来自反代自己记录的 upstream_model(上游在响应帧里自报的显示名)。
不能靠响应体判断:反代回给客户端的 "model" 填的是你请求的那个,响应体本身在撒谎。
已知边界
- 判定表是插件内置的:反代新增模型后要更新插件(否则新模型一律
unknown,不误报); - 每次在最近 5 条请求里找「最近一次可判定的」:最新一条是生图时会继续往前找, 不会因为一条判不了的请求就把更早的降级藏起来;
- 它不能阻止这一次降级——那要在反代里做(上游
strict_model)。插件负责让你 知道,以及下一步换号。
宿主路由
| 路由 | 上游 | 说明 |
|---|---|---|
| GET /plugins/dsh-gemini-quota/quota[?account_id=N][?refresh=1] | GET /admin/api/quota | 额度条数据;account_id 是面板逐号查的入口 |
| GET /plugins/dsh-gemini-quota/pool | GET /admin/api/cookies | 账号池视图(健康度、失败计数、代理、cookie 摘要) |
| GET /plugins/dsh-gemini-quota/actual[?limit=N] | GET /admin/api/requests | 降级守卫:最近几次请求「请求的模型 vs 实际用的模型」(只回元数据,不含 prompt/正文) |
| POST /plugins/dsh-gemini-quota/account | POST /admin/api/cookies/{id}/{toggle\|check\|rotate} | 账号动作;switch 由插件编排(启用目标 + 停用其余) |
sapisid_tail 之类的摘要字段来自反代;完整 cookie 值不会出现在任何回给浏览器的数据里。
工作原理
- 宿主半(
index.js)把反代/admin/api/*转成同源路由/plugins/dsh-gemini-quota/*。 为什么不让浏览器直连反代:反代的 CORS 预检没有Access-Control-Allow-Headers,带Authorization的 fetch 会被浏览器拒;用?token=又能过但会把 admin token 泄进前端产物。 - 四条路由都自带最小信任闸门(回环对端 + 回环 Host + 非 cross-site + 同源 Origin),
POST /account另有readOnly开关和入参校验。 - 面板的逐号额度是打开面板时才按需并发查(3 个 worker),一旦发现反代不支持
?account_id=N就立刻停手并如实标注,不白打上游。 - 路由同时下发
providers/matchModelPrefix:浏览器半拿不到 cordis config (client-modules 只传{ name: id }),所以门控范围必须由宿主告知。 - 降级判定必须在宿主半做:响应体里的
"model"是「你请求的」(反代原样回填), 真相只在上游自报的upstream_model里,而那个字段只有反代的 admin API 才给得出来。
自测
node --check index.js && node --check client.js
node selftest.mjs # 20 项:路由/闸门/token 链/字段映射 + 降级判定 7 情形(stub 上游)
# + 额度条渲染(降级亮灯 / 正常不误报)+ 浏览器半契约冒烟
node scripts/http-check.mjs # 真起一个 http server,用真 fetch 打一遍三条路由反代没在跑时依赖上游的用例会标 SKIP 而不是失败。
疑难排查
| 现象 | 原因 |
|---|---|
| 悬停提示正常但条一直不出现 | 当前模型不在 providers 里;改配置或开 matchModelPrefix |
| 额度条染成警告色 + ⚠️ | 最近一次请求被静默降级(响应体里看不出来,悬停看「请求 X 实际 Y」) |
| 降级判定一直是 unknown(不亮灯) | 上游没自报显示名,或该模型不在插件内置表里——这是刻意的,不是故障 |
| 控制台/路由 503 no admin token | token 四个来源都没命中 |
| 502 upstream ... | 反代没跑、端口不对、或 admin token 无效 |
| 面板整行都显示 — 并提示「按号查额度不支持」 | 反代的 /admin/api/quota 没打 ?account_id=N 扩展(见文件头说明) |
| 403 forbidden | 不是从回环地址/同源访问的 |
| 点「停用」提示 403 readOnly | 宿主配置里把 readOnly 设成了 true |
| 切号后发现请求还是走旧号 | 调度器每请求取一次号;已在飞的请求不会中断,下一条新请求才走新号 |
| 改了 client.js 界面没变 | client-hmr 对 link: 安装不一定生效,刷新页面(Cmd+R)最稳 |
| 改了 index.js(宿主半)界面没变 | 宿主半没有 HMR:需要重启 DSH(或插件页关掉再开启该组合包) |
| 刚发布的新版装不上(Already up to date) | pnpm「最小发布年龄」保护:加 --config.minimumReleaseAge=0,或等一段时间 |
卸载
插件页关掉组合包,或 dsh plugin --profile <profile> remove dsh-gemini-quota。
License
MIT
