upcyan/dsh-mimo-extension ↗★ 0
dsh-mimo-extension
mi logo + quota ring beside the model selector, plus a MiMo usage detail tab (billing type, plan quota, per-session attribution, cost estimate). 适合需要实时监控 MiMo 官方额度和套餐使用情况的用户。
설치
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:upcyan/dsh-mimo-extension配置
Cookie
填了 Cookie 才能读到官方额度。
| 字段 | 作用 |
|---|---|
| MiMo 控制台 Cookie | 官方接口鉴权。留空表示保持不变;勾「清除已保存的 Cookie」可清掉 |
| 本地兜底套餐总量 | 没配 Cookie 时,用来估算月度总量的 tokens 数 |
| 额度胶囊位置 | 见下 |
| 允许输入框工具栏自动换行 | 见下 |
| 启用 MiMo 视觉路由 | 见下 |
保存的值写进 $DSH_HOME/settings.yaml 的 dsh-mimo-extension 命名空间,优先级高于 cordis.patch.yml 里的 config(后者只作组成基线)。
这个 Cookie 是给套餐用的
同一个控制台 Cookie 打三个接口,Token Plan 的数据依赖它:
| 接口 | 读什么 | 归属 |
|---|---|---|
tokenPlan/detail | 套餐码、周期、是否过期 | Token Plan |
tokenPlan/usage | 已用百分比、各项 items | Token Plan |
balance | 现金和赠金余额 | 按量 |
套餐用户不填 Cookie,剩余百分比就读不到(两个 tokenPlan/* 都返回 401),只能退回本地估算。按量用户填了也只多一个 balance,按量本来就没有 tokenPlan/usage。
实测(2026-09-27,有效 Cookie):
curl -H "cookie: " https://platform.xiaomimimo.com/api/v1/tokenPlan/detail
# → {"code":0,"data":{"monthUsage":{"percent":0.1186,"items":[{"name":"month_total_token",...}]}}}
Cookie 是几百字符的长串,输入框支持 Ctrl+V、右键粘贴,另有一个「粘贴」按钮走 navigator.clipboard.readText() 兜底(无权限或非安全上下文会提示手动粘贴)。输入框是 type="text" 而非 password,粘贴不受浏览器对密码字段的限制,内容也能看见便于核对。
获取步骤(表单里也有):
- 登录
- DevTools → Network → 任一
/api/v1请求 → Headers → 复制完整Cookie请求头 - 确认含
api-platform_serviceToken与userId,整段粘进表单保存
不用界面也行:写进 $DSH_HOME/.credentials.yaml 的 refs.MIMO_CONSOLE_COOKIE,或直接编辑 cordis.patch.yml 的 mimo.cookie。
Cookie 只存本机 settings.yaml,不回传给浏览器。读取接口只返回「是否已配置 + 来源」,输入框也不回显明文。
胶囊位置
在「MiMo 用量」页底部的表单里选,保存即生效:
| 取值 | 位置 | 说明 |
|---|---|---|
header | 标题行 | 与「对话 / 轨迹」同一行的右侧动作区 |
toolbar(默认) | 输入框工具栏 | 模型选择器旁,即 codebuddy 用量环的位置 |
above | 输入框上方 | 独占一行,最不挤占其它工具 |
hidden | 不显示 | 只留详情页 |
点击环弹出的摘要卡,不管胶囊在哪个座位都用 createPortal 挂到 document.body,再按锚点位置和视口空间摆位:水平越界就左移、贴顶就翻到下方、resize 和滚动时重算、内容过高时内部滚动。祖先的 overflow 裁不到它,320px 窄屏和 800×360 横屏下都完整可见。
工具栏自动换行
插件多了以后,输入区的工具图标会互相挤压重叠。表单里的「允许输入框工具栏自动换行」(默认开)注入的样式只作用于组内(_tools / _actions / 左右槽位容器),让图标在本组内折行,不动整行。整行是否换行由产品原生样式决定;装了 dsh-web-mobile-cyanmod 时会被它覆盖成 nowrap,两者可以叠加。关掉立即恢复官方默认。
视觉路由
在「MiMo 用量」页底部勾选「启用 MiMo 视觉路由(图像输入)」。
平台按模型的 inputModalities 拦图片附件,dsh-api-session-controller 会抛 MODEL_DOES_NOT_SUPPORT_IMAGES。这个值来自 llm-pi-ai 里每个模型的 input 字段。开启后插件把多模态模型的 input 写成 ["text","image"],图片就能发给它们。
只对平台目录声明支持图像的模型生效(数据来自 pi-ai 的 dist/providers/data/xiaomi*.json):
| provider | 模型 | catalog 的 input | 本开关 |
|---|---|---|---|
xiaomi / xiaomi-token-plan-{cn,sgp,ams} | mimo-v2.5 | ["text","image"] | 写入 |
| 同上 | mimo-v2.5-pro | ["text"] | 不碰 |
xiaomi | mimo-v2.5-pro-ultraspeed | ["text"] | 不碰 |
不给纯文本模型撑腰是有意的:硬声明图像支持会把失败从"明确拒绝"变成"图片被上游静默丢弃",而后者用户以为发出去了。自建 provider(比如 mimo)也不在内置表里——它的模型清单由你自己声明,能力也该由你自己声明。
写入用 settings.mutate("llm-pi-ai", ops) 整条替换 models 数组,只改目标模型的 input,不重写整个 provider。已经是 ["text","image"] 就不写;关闭时去掉 image 并保留其它模态(空了补回 ["text"])。启动时会再同步一次,因为开关可能比写入活得久(插件重装、配置被改)。
写入失败会回显:POST /settings 回传 visionChanged / visionError,表单显示"已开启:``"或失败原因,不会只报"已保存"。
这是跨命名空间写入(改的是 llm-pi-ai)。平台 settings.write() 只校验命名空间已注册,不校验调用者归属,所以可行;但只读 provider 上会失败并报错。
子选项:同时为纯文本模型提供视觉能力
主开关下方还有一个「同时为纯文本模型提供视觉能力」,默认关,且主开关关时禁用。它额外给平台标为纯文本的小米模型声明图像输入:
| provider | 模型 | catalog input |
|---|---|---|
xiaomi | mimo-v2.5-pro、mimo-v2.5-pro-ultraspeed | ["text"] |
xiaomi-token-plan-{cn,sgp,ams} | mimo-v2.5-pro | ["text"] |
这是越权声明:上游可能拒绝,也可能静默丢图(你未必收到报错,比明确报错更麻烦)。确认这些模型实际能读图时再开。
回收是精确的。两张模型清单(多模态 / 纯文本)各自决定自己去留,关掉子选项时只回收它加过的,不会删掉 catalog 本就给 mimo-v2.5 声明的 image——那归主开关管。
显示规则
只在用 MiMo 模型时显示
额度环绑在 MiMo 通道上,所以只在当前模型属于 MiMo 时渲染。读会话投影 modelSelection 的 next / lastUsed,与 dsh-codebuddy 的 codebuddyUsageVisible 同一机制。
判定以 API 地址为准,名字只作参考。平台内置 catalog 里的小米路由有两类命名:xiaomi(按量)和 xiaomi-token-plan-cn / -sgp / -ams(套餐),它们都不含 mimo;反过来,自建网关可以叫 mimo-xxx 却指向别家。所以:
- 地址是
xiaomimimo.com域名 → 是 - 地址明确是别家 → 不是
- 地址读不到 → 退回名字(provider 名含
mimo/xiaomi*,或模型名含mimo)
用别的 provider(比如 codebuddy)时整个环不渲染,免得"明明没用 MiMo 却在报 MiMo 额度"。这时候详情页会在模型卡下标注「当前模型属于 X,不是 MiMo,下面的套餐额度是 MiMo 账号级的」。读不到 provider 时保持显示,宁多显示也不因读取失败静默关掉功能。
详情页可以设成「非 MiMo 时隐藏」:开启后不是 MiMo 就把整个 tab 收掉,切回 MiMo 自动恢复。默认关闭(一直显示)。
会话用量按渠道归属
一个会话可以换过模型,所以 session.totalTokens 不等于 MiMo 用量。实测某会话:
mimo/mimo-v2.6-flash 49,771,661 tokens / 367 calls
codebuddy/deepseek-v4.1-flash 89,081,411 tokens / 414 calls
─────────────────────────────────────────────────────────
总计 138,853,072 tokens(其中 64% 不是 MiMo)
插件按 models[].provider 只统计 MiMo 归属的部分,三种情形都有交代:
| 情形 | 显示 |
|---|---|
| 会话混用了多个渠道 | 汇总只算 MiMo;下方列出各非 MiMo 渠道并声明「不计入上方汇总」;费用标注「估算」(分渠道明细只有总量、没有输入输出拆分,按 token 占比折算) |
| 本会话完全没用 MiMo | 提示「本会话尚未使用 MiMo,会话用量为 0 是正常的」,并说明下方套餐额度是账号级的、与会话无关 |
| 无分渠道明细(老计数器或统计降级) | 标注「未细分渠道」,退回整体计数。不猜测,也不把数据抹成 0 |
明细表给非 MiMo 行加「不计入 MiMo」标记并弱化,另加 % 列显示各渠道占比。
早期版本用整会话的 input/output 乘 MiMo 单价算费用,会话换过模型时会把别的渠道的消耗也算进来,费用因此偏高。
尺寸与外观
额度环对齐 dsh-codebuddy 的用量环,两者并排时大小一致:
| 项 | 值 | 对应 codebuddy |
|---|---|---|
| 环直径 | 26 | Progress type="circle" width={26} |
| 环宽 | 3 | strokeWidth={3} |
| 中心 logo | 12 | CodeBuddyLogo size={12} |
| 环底圈 | --dsw-alias-border-l3 | orbitStroke |
| 环进度 | --dsw-alias-label-tertiary | stroke |
| logo 底色 | #ff6900(小米品牌橙) | variant="brand" 的写死色 |
| 起点 | rotate(-90),12 点方向顺时针 | Semi 默认 |
尺寸不随窄屏或紧凑模式缩小,紧凑场景靠去掉内边距解决。配色用平台主题变量(dsh-web-frontend 定义),自动跟随主题。
logo 用固定品牌色而不是主题变量 --dsw-alias-brand-primary,因为本机主题把那变量定义成 #0f1115(近黑),环心会变成一团看不清的黑块。品牌 mark 保持品牌色,codebuddy 也这么干(它的 CodeBuddyLogo 在默认变体下写死 #6C4DFF,只有 mono 变体才用主题变量)。
codebuddy 用 @douyinfe/semi-ui 的 Progress,而 semi 不在平台 seed 表里(它自己打进了 6.5MB bundle)。本插件手写等价的 SVG 双圈,零依赖。mi logo 用 simple-icons 的 xiaomi 路径。
移动端竖屏
窄屏(<640px)自动切布局:
- 详情页各卡片区从多列改单列堆叠,内边距与字号收窄
- 按模型的表格外层可横向滚动,不撑破卡片
- 用量柱状图降低柱高(60px → 46px)并允许横滚
- 胶囊在窄屏隐藏文字,只留百分比或用量数值,避免挤压会话标题
宽屏(≥640px)保持多列自适应。横竖屏切换和窗口拖动都会实时重排。
数据与计费
数据来源
官方接口优先(需 Cookie):
GET https://platform.xiaomimimo.com/api/v1/balance— 余额 / 现金 / 赠金GET https://platform.xiaomimimo.com/api/v1/tokenPlan/detail— planCode、currentPeriodEnd、expiredGET https://platform.xiaomimimo.com/api/v1/tokenPlan/usage— monthUsage{percent, items[{name, used, limit, percent}]},percent 需 ×100- 鉴权:请求头带
Cookie(含api-platform_serviceToken与userId)
本地估算兜底(Cookie 没配或接口失败):
- 聚合
$DSH_HOME/token-usage/usage-*.jsonl的本月用量 - 除以
mimo.planTotalTokens(默认 5 亿/月)得剩余百分比 - 详情页顶部标注「本地估算(官方接口不可用)」
内置会话统计(token-usage/ 目录不存在时):
token-usage/和ctx.tokenUsageCounter都由dsh-token-usage-counter提供。该插件没装进 profile 时目录根本不存在,旧行为是把ENOENT ... scandir '.../token-usage'当错误抛出来,而且「今日/本月 tokens」「当前会话用量」永远是 0。- 现在目录缺失按「暂无记录」处理(
local.ok=true, local.missing=true, local.note说明原因),并由createLocalUsageCounter()直接读会话事件(assistant/message.data.usage)自建统计填上数值,来源标local.source = "session-events"。 - 口径是进程启动以来仍存活的会话,重启归零。它只读不落盘;一旦
dsh-token-usage-counter装回来并有数据,仍以它的落盘数据为准。 - 去重靠事件
seq,/session每 60 秒重复扫描不会把用量翻倍。
计费类型判定
顺序如下(billingTypeFor()):
-
mimo.billingTypeOverrides(provider/model或provider)—— 用户说了算 -
provider 的 API 地址(从
llm-pi-ai命名空间读)。小米两条通道的地址不同(pi-ai 官方目录providers/*.json实测):计费方式 目录里的 provider baseURL 按量付费 xiaomihttps://api.xiaomimimo.com/v1Token Plan xiaomi-token-plan-cnhttps://token-plan-cn.xiaomimimo.com/v1Token Plan xiaomi-token-plan-sgphttps://token-plan-sgp.xiaomimimo.com/v1Token Plan xiaomi-token-plan-amshttps://token-plan-ams.xiaomimimo.com/v1地址含
token-plan→ 套餐;是xiaomimimo.com其余子域 → 按量;读不到(自建网关、命名空间缺失)→ 继续往下。 -
provider 名含
token-plan→ 套餐 -
provider 是小米通道但地址没读到 → 用官方
tokenPlan/detail反证(summary.planStatus四态):expired(已过期)或none(官方明确无订阅)→ 按量;active/unknown(没配 Cookie、接口失败)→ 套餐 -
其余 provider → 按量
想强制某条路由按量(或反过来),写 billingTypeOverrides: { mimo: payg }。
单价按量模型用 mimo.pricing. (元/百万 tokens),没配则用 fallbackPrice。Token Plan 套餐内调用不额外收费。
「当前模型」从哪读
判定用的 provider / model 是当前选中的,不是最近一次请求用过的:
| 优先级 | 来源 | 语义 |
|---|---|---|
| 1 | agent-default-model 命名空间 | 用户此刻选的是什么(切模型立即写入,与 UI 同源) |
| 2 | session/event 的 request/header | 最近一次真的发过请求用的是什么 |
| 3 | 落盘计数器快照 | 历史 |
| 4 | 内置统计快照 | 历史 |
| 5 | 空 | 计费退化为 provider 命名约定 |
第 1 级必须在第 2 级之前。早期只有 2~4 级,于是在 UI 里把模型切到 MiMo 但还没发消息时,仍按旧模型判定,显示"按量付费"而模型选择器已经是 MiMo。这个顺序是有语义的。
数量单位
小米 Token Plan 的额度单位是 Credits,不是 tokens,也不是人民币;按量付费才是人民币余额,两者不通用:
-
订阅套餐时
/api/v1/balance恒为 0,这是正常的,详情页会标注说明 -
官方换算(每百万 token 消耗的 Credits):
模型 缓存命中 缓存未命中 输出 mimo-v2.6-pro 2.5 300 600 mimo-v2.6-flash2 100 200 mimo-v2.5-pro 2.5 300 600 mimo-v2.5 2 100 200 -
闲时 0.8 倍:北京时间 00:00–08:00 只扣 80%
-
用量到 50% / 90% / 100% 时官方发短信和邮件
tokenPlan/usage 返回的 percent 是 0~1 的比值,要 ×100 才是百分比。实测 used/limit = 4725102737/49200000000 = 0.096038,接口回 percent: 0.0960;控制台前端的换算是 Math.min(100, Math.max(0, 100 * e)),所以官网显示 9.6%。本插件 toPercent() 用同一口径。早期版本直接当百分数显示,「本月已用」只有真实值的 1/100。
排查「装了没生效」
浏览器里看不到胶囊或详情页这类问题,服务端看不见。所以浏览器半边每走一个节点就往宿主 POST /dsh-mimo-extension/ping 报一次,从 /summary 的 client 字段读结果:
## 从 dsh-mimo-usage 升级
插件原名 `dsh-mimo-usage`,2026-09-27 改名为 `dsh-mimo-extension`,仓库和包名同步改了。
配置不用手工搬。启动时会自动把旧命名空间 `dsh-mimo-usage` 里的用户配置(含 Cookie、套餐总量、胶囊位置、各开关)迁移到 `dsh-mimo-extension` 段。迁移单向、幂等(新段已有配置就不覆盖),且**不删除旧段**,留作回滚依据,确认无误后可自行清理。
迁移只搬 `mimo` 子对象。旧段里手工加过其它字段的话需要自己处理。
profile 里的旧依赖(`file:dsh-mimo-usage-*.tgz`)不会自动消失,需要先 `dsh plugin remove dsh-mimo-usage` 再装新的。