> 🤖 **本内容由 AI 编码代理生成,非人类手写。**
> **This was generated by an AI coding agent, not written by a human.**
>
> - Agent: blancatora (DeepSeek Harness 编码代理)
> - Model: deepseek-v4.1-flash
> - Contact: blancatora@agent.qq.com
>
> **免责声明 / Disclaimer**:本内容由上述 AI 代理生成,可能存在错误、不完整或未经充分
> 验证的结论。**账号所有者未参与本内容的编写与决策**,不对其内容与后果负责;也不代表
> 任何第三方的立场。使用前请自行核实。
> This content was produced by the AI agent named above. It may contain errors, omissions,
> or unverified conclusions. **The account owner did not write or decide on this content**
> and is not responsible for it or its consequences. Please verify before relying on it.
dsh-opendesign-usage
在 DSH 输入框里看 Open Design 的套餐额度与本会话 token 用量。
English ·
安装 ·
功能 ·
配置 ·
工作原理 ·
署名与声明 ·
更新日志
一个独立的 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle 插件。
它在输入框左下角的工具行加一个**只读读数**:显示 Open Design 套餐额度两个窗口(5 小时 / 7 天)的剩余百分比。
钱包余额与本会话 token 用量在明细里、**不常驻读数**。读数**只在会话选中 `opendesign` 模型时出现**,
切到别的 provider 就干净消失,不会占着工具行的位置。所有功能都可以在插件详情页自行开关。
```
OD · 90% · 97%
│ └────── 7 天窗口剩余额度
└───────────── 5 小时窗口剩余额度
```
读数只留两个额度窗口 —— 工具行那格宽度有限,塞进 token 与钱包会明显过长。
**钱包余额、本会话 token、每个窗口的重置倒计时都在点开的面板明细里。**
## 功能
### 1. 套餐额度
读 Open Design 控制台的 `coding-plan-usage` 接口,显示两个滚动窗口的剩余额度。
点开面板看明细:
| 窗口 | 剩余 | 重置 |
|---|---|---|
| 5 小时额度 | 50%(24,960 / 50,000 credits) | 1 小时 38 分后 |
| 7 天额度 | 87%(130,918 / 150,000 credits) | 6 天后 |
- 倒计时用上游返回的**服务端相对值**(`resetsInMs`),不是拿 `resetsAt` 与本地时钟相减 ——
你的机器时钟偏了也不会算错。
- 取不到的窗口显示 `—` 而**不是省略**:两个位置恒定,避免把 7 天错读成 5 小时。
### 2. 钱包余额
套餐用尽后的兜底余额(订阅额度 + 充值额度),在面板明细里显示。
> 钱包跟随「套餐额度」开关:它是「套餐用尽后的兜底余额」,
> 没有套餐语境单独显示一个美元数会让人不知道那是什么钱。
### 3. 本会话 token 用量
读宿主的 `tokenUsage` 投影,在面板明细里给出合计与分项
(输入 / 输出 / 缓存读 / 缓存写)。**纯读宿主数据,不需要任何凭据。**
### 4. 在插件详情页自行开关
| 开关 | 默认 | 作用 |
|---|---|---|
| `enableComposerUsage` | 开 | 是否在输入框显示这个读数控件 |
| `enablePlanQuota` | 开 | 是否显示套餐额度**与钱包余额**(两者都需要凭据) |
| `enableTokenUsage` | 开 | 是否显示会话 token 用量 |
关掉 `enableComposerUsage` 后控件完全不注册、不发任何请求。
关掉 `enablePlanQuota` 后宿主连上游都不打 —— 不会出现「关了还在后台刷」。
## 安装
### 前置条件
- 一个可用的 DSH 安装(本插件在 **0.2.1-alpha.2** 上开发与验证);
- 想在读数额度的话,需要一个 Open Design 账号(免费注册即可)。
### 安装插件
DSH 自带插件管理器。在 GUI 里:
1. 侧栏点 **插件**;
2. 点 **添加插件**(或箭头 → **安装第三方插件**);
3. 填入下表中对应的一行,回车:
| 安装方式 | 填什么 |
|---|---|
| npm(**推荐**,等发布后可用) | `dsh-opendesign-usage` |
| Git 仓库 | `https://github.com/<你的用户名>/dsh-opendesign-usage` |
| 本地目录 | `/绝对路径/to/dsh-opendesign-usage` |
管理器会调用 pnpm 把包装进当前 profile,并给出「立即启用」。
手动安装(不使用 GUI 插件管理器)
```sh
# 1) 把包放进 profile 的依赖
cd ~/.dsh/profiles/
pnpm add /绝对路径/to/dsh-opendesign-usage
# 2) 把它加进 profile 的 bundle 列表
# 编辑 ~/.dsh/profiles//package.json,在 dsh.profile.bundles 末尾追加:
# "dsh-opendesign-usage"
# 3) 重启 DSH
```
### 启用
装好后**重启 DSH**(新增 bundle 需要重新组装 profile)。
然后在会话里把模型切换到任一 `opendesign` 模型 —— 输入框左下角就会出现读数。
> 读数不出现是正常的:它只在会话选中 `opendesign` provider 时渲染。
> 用别的 provider 时它不占位、不发请求。
## 配置
设置的位置在**插件详情页**,不在「设置」总页:
> 侧栏点 **插件** → 找到 **Open Design Usage** → 在它自己的页面里改配置。
这是 DSH 的既定分工 —— 插件管理器的说明原文:
「注册了配置页的插件在这里、在它自己的页面上编辑;设置里只保留只读的插件列表。」
改完点**保存**生效(三个开关与各输入框统一暂存、一次提交)。三个功能开关、
`workspaceId` / `sessionCookie` / 刷新间隔都在这一页;
「测试连接」按钮可以**不保存**先用草稿值试一次凭据。
### 拿 workspaceId
登录 [Open Design 控制台](https://open-design.ai),地址栏里的 `workspaceId` 参数即是:
```
https://open-design.ai/cloud/dashboard?workspaceId=<你的 workspaceId>
^^^^^^^^^^^^^^^^^^ 复制这一段
```
### 拿 sessionCookie
1. 浏览器登录 Open Design 控制台;
2. `F12` 打开开发者工具 → **Network** 标签 → 刷新页面;
3. 筛选框输入 `coding-plan-usage`;
4. 点开那个请求 → **Request Headers** → 找到 `Cookie` 行;
5. 复制 `__Secure-better-auth.session_token=` **后面**的值(到 `;` 为止)。
> 直接整段粘贴 `Cookie` 头也可以,插件会自动挑出那个 token。
> 该字段**不回显明文**(用 primitives 的 `SettingsSecretField`:每次为空,只报告是否已配置)。
⚠️ **这是一个登录凭据。** 它等同于你的控制台登录态:
- 插件把它存在 DSH 的本地设置里,**只**用于向 `amr-api.open-design.ai` 读你自己的额度;
- 插件不收集、不上传、不转发到任何第三方;
- 它会过期(better-auth 的会话有期限),过期后读数会显示 `—`,重新走一遍上面的步骤即可;
- 如果这台机器不是只有你用,建议关掉 `enablePlanQuota`,只用不需要凭据的 token 用量。
### 刷新间隔
默认 5 分钟,允许 1–60 分钟。**只在读数可见且套餐开关打开时才发请求**,
所以它不会在后台常驻刷接口。
## 工作原理
```
输入框读数(浏览器)
│ GET /plugins/dsh-opendesign-usage/plan-usage ← 同源路由,宿主侧实现
▼
DSH 宿主(src/index.js)
│ GET https://amr-api.open-design.ai/api/v1/workspaces/{id}/billing/coding-plan-usage
│ GET https://amr-api.open-design.ai/api/v1/billing/summary
▼
Open Design 控制台 API
```
三个设计选择值得说明:
**① 凭据只在宿主侧使用,浏览器侧拿不到。** 客户端从不直接打上游:
它请求宿主的同源路由 `/plugins/dsh-opendesign-usage/plan-usage`,
由宿主带上 cookie 去打上游、归一化后再返回。这样凭据不必进入页面上下文。
**② 路由做 loopback 来源校验。** 两条路由(`plan-usage` / `test-connection`)
都只接受来自本机 loopback 或 DSH 自身协议(`dsh-app:` / `dsh:`)的请求。
带凭据的接口不该被任意网页调用。
**③ 两个上游接口独立成败。** 额度与钱包是两个独立接口,
任一失败都不清掉另一个的读数 —— 面板里能同时看到「额度拿到了、钱包暂时读不到」。
### 为什么是 `conversation.input.left`
输入框工具行是 **per-session 且按 provider 归属**的:读数只在选中 `opendesign` 的会话里出现,
天然只有一个插件关心那一格。相较之下,侧栏底部是**单个 root 级共享行**,
多个连接器插件会互相挤压。
### 为什么 gate 用 `modelSelection` 投影
读数「该不该出现」由会话当前选中的模型决定,而那是宿主已经算好的投影。
注册是无条件的、由组件自己 `return null` —— 条件注册会在 provider 切换时留下空位
(注册表按 id 记账,撤掉再注册有竞态),而无条件注册 + `return null` 是零成本的。
## 兼容性
- **DSH**:0.2.1-alpha.2(开发与验证版本)。插件用到的插槽与官方组件都在
`dsh.client.inject` 里声明;
- **Node**:`^22.19.0 || >=24.0.0`;
- **平台**:`web`(DSH 的 Web GUI)。
### 权限与数据
| 项 | 说明 |
|---|---|
| 网络 | 宿主侧只连 `amr-api.open-design.ai`;客户端只连宿主同源路由 |
| 读凭据 | `workspaceId` + 会话 token,存在 DSH 本地设置;**不回显明文** |
| 上传 | 无。插件不收集、不上传任何数据到第三方 |
| 文件 | 不读写工作区文件 |
## 开发
```sh
node src/build-client.mjs # 由 src/ 生成 lib/client.js
node --test test/*.test.mjs # 单元测试
```
⚠️ `lib/client.js` 是**生成物**,不要手改;改 `src/` 后重新构建。
构建脚本带**产物守卫**(`src/build-client.mjs` 的 `assertBundleShape()`):
产物必须能被解析,且 `require` 只允许 seed 表里的 9 个模块。
坏产物**在构建期就失败**,不会落盘 —— DSH 客户端插件的坏产物表现是整站白屏
且 crash log 没有堆栈,必须靠构建期拦住。
### 规范文档
- **[docs/plugin-development.md](docs/plugin-development.md)** —— DSH 客户端插件开发规范。
`inject` 的两套语义、`apply` 不得抛错、`require` 的 seed 表白名单、
错误信息解读(`import failed` 是兜底文案,不是"导入失败")、构建期守卫、
真实产物接线层测试、pnpm 硬链接、发布前 checklist。
- **[docs/design-guidelines.md](docs/design-guidelines.md)** —— DSH 插件 UI 设计规范。
用官方 `primitives` 组件而不是自绘、只用主题 token、
常驻读数要精简、交互方式跟宿主一致。
- **[CREDITS.md](CREDITS.md)** —— 署名、AI 协作声明与第三方来源。
- **[CHANGELOG.md](CHANGELOG.md)** —— 变更记录。
## 许可
[MIT](LICENSE)。署名与 AI 协作声明见 [CREDITS.md](CREDITS.md)。
这是**非官方**第三方插件,与 Open Design(AMR)官方无隶属关系,未获其背书。