dsh-router
No description
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 28, 2026
- Updated
- Aug 29, 2026
Introduction
dsh-router
插件版的 9router —— 不是另开一个网关服务,而是直接作为 DSH 插件嵌进
DSH web(和「记忆系统」同侧边栏),在 http://localhost:3080/v1 上原生暴露
OpenAI 兼容端点,把请求路由到内部供应商。装好即用,不用多开一个 9router、
不用维护第二个端口、不用在网关和 DSH 之间搬配置。
为什么更优雅
- 零额外进程:dsh-router 就是 DSH 插件,随
dsh web启停,天然同源 (/router/api/*无 CORS、面板内嵌侧边栏),不像 9router 要独立跑一个 Next.js 服务再对接; - 供应商即插即拔:内置供应商(如 opencode / openrouter / nvidia)随插件分发;
更多供应商 = 装一个 DSH 插件(
dsh-router-*)经 cordis servicerouter.suppliers注册,面板自动出现、热加载/卸载;也可以放一个自定义 js 文件到~/.dsh/profiles/web/suppliers/就注册一个新供应商—— 无需改核心代码、无需重编译; - 模型不内置:供应商只实现差异化能力(列模型/调上游/登录),模型拉取与 缓存由核心统一管,不写死、不过时;
- 通用能力只写一次:连接池回退、账号冷却、签到规则、凭证存储、模型管理都由 核心提供。连「测试模型」都是核心走真实对话路径跑的——供应商不重写这份逻辑, 就不会出现「只试第一个账号」这种分不清额度还是模型的测试;
- 凭证 SQLite 单库:
auths/credentials.sqlite,供应商凭证不透明 blob, 核心统一生命周期,干净可备份; - 复用 9router 思路:面板布局、组合 fallback、连接池/账号池、API key 管理都贴近 9router,但按 DSH「一切皆插件」的方式重组得更轻。
供应商开发与接入规范见
docs/suppliers.md(契约 / 加载顺序 / 模型统一策略 / 内置供应商参考实现)。
左侧边栏「记忆系统」上方有 路由系统 入口,点击打开中心栏面板:
- 返回会话 — 左侧按钮,关闭面板回到聊天;
- 供应商 — 供应商卡片(内置 / 插件分组),点击进入详情:
- 链接池 — 账号列表(冷却/禁用/健康数/积分),支持删除;
- 加链接 — 按供应商能力弹出不同流程:URL 登录(生成链接 → 浏览器登录 → 回调)、 API key 弹窗(填名字 + key)、轮询登录(登录后自动取凭证);
- 签到 — 供应商实现了签到的才显示(如 codebuddy:每日 100 积分,连续第 7 天 1000)。签哪些账号由核心通用策略定(所有链接 / 仅首个);上游「今日已签到」按成功 处理(幂等),账号额度或凭证失效会单独标出;
- 可用模型 — 模型列表,逐个启用/禁用 + 自定义模型(通用能力,持久化到
data/supplier-config.json,/v1/models与 chat 只接受启用的模型);单个模型可 「测试」,走真实对话路径并按账号池依次回退,所以能分清是这个账号额度没了还是 该模型真的不支持;
- 组合 — fallback 链(免费优先),可自定义。组合即模型:建好的组合会自动带出
为 DSH 模型目录里的
routerprovider 选项(设置 → 模型直接选组合名即可用),请求 按组合策略命中其中一个供应商模型; - 端点与密钥 — 端点核心(无隧道/Tailscale):
- API 端点 URL(
http://localhost:3080/v1,可复制); - 鉴权设置
requireApiKey开关; - API Keys 管理:创建 / 启用切换 / 显示 / 复制 / 删除(持久化到
data/keys.json)。
- API 端点 URL(
API 端点(OpenAI 兼容,:3080/v1)
# 模型列表
curl http://localhost:3080/v1/models
# 对话(流式/非流式)
curl -X POST http://localhost:3080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"glm-5.2","messages":[{"role":"user","content":"你好"}],"stream":false}'
任何支持 OpenAI 兼容 API 的工具(Claude Code、Cline、DSH 设置-模型 等)都可以把
baseURL 指向 http://localhost:3080/v1。
鉴权:默认 requireApiKey=false,/v1/* 不要求鉴权(本地使用,与 9router 一致)。
在「端点与密钥」页开启「要求 API Key」后,请求必须带
Authorization: Bearer <库内启用的 Key 或 TW2A_API_KEY>。
面板 API(/router/api/*,同源)
| 端点 | 方法 | 说明 |
|---|---|---|
/health | GET | 供应商列表(含来源/能力) |
/status | GET | 全部账号(含供应商 id) |
/models | GET | 合并模型列表(已过滤禁用) |
/combos | GET | 组合 fallback 链 |
/keys | GET/POST | 密钥列表(含完整 key)/ 创建 {name} → 返回明文一次 |
/keys/toggle | POST | {id, isActive} |
/keys/delete | POST | {id} |
/settings | GET/PATCH | {requireApiKey} |
/suppliers/:id/login | POST | 生成登录链接 |
/suppliers/:id/login/callback | POST | {callbackUrl} → 加账号 |
/suppliers/:id/models | GET | 模型 + 启用状态 |
/suppliers/:id/models/toggle | POST | {id, enabled} |
架构
浏览器(client 半)
└─ 侧边栏「路由系统」+ 中心栏面板(RouterView, 含返回会话按钮)
├─ RouterView tab: 供应商 / 组合 / 端点与密钥
├─ SupplierDetail 供应商详情:链接池 + 加链接 + 可用模型
├─ EndpointTab 端点 URL + requireApiKey + 密钥管理
└─ fetch /router/api/* (同源,无 CORS)
└─ host 半(src/index.ts)
├─ /v1/models + /v1/chat/completions (OpenAI 兼容, KeysStore 鉴权)
├─ KeysStore(src/keys.ts) 密钥库 + requireApiKey
└─ Router(路由器) → suppliers[]
├─ OpenCodeSupplier(lib/suppliers/opencode.js) 无账号免费直连
├─ OpenRouterSupplier(lib/suppliers/openrouter.js) API key 账号
└─ NvidiaSupplier(lib/suppliers/nvidia.js) API key 账号
└─ 外部插件供应商(经 router.suppliers service 注册)
- 供应商抽象:可插拔 js 模块只提供差异化能力(
status/listModels/getAlias/chatCompletions- 可选登录/签到/测模型);通用能力(连接池排序/策略、模型启用/自定义、别名、凭证) 由核心统一管。
- 供应商加载(三来源,见
docs/suppliers.md):- 内置:
lib/suppliers/*.js(随插件分发,如 opencode) - 用户:
~/.dsh/profiles/web/suppliers/*.js - 外部插件:其他 DSH 插件通过 cordis service
router.suppliers(值为{ [supplierId]: (env) => SupplierModule })暴露供应商, dsh-routerctx.inject(['router.suppliers'])延迟加载。
- 内置:
- 模型统一策略:插件不内置、不缓存模型;
listModels每次从上游拉取, 缓存由核心按 60s TTL 统一管(/suppliers/:id/models),/v1/models保持实时。 - 凭证存储:SQLite 单库
{authDir}/credentials.sqlite(表credentials(supplier, uid, data), 凭证为供应商不透明 JSON blob)。 - /v1/* 鉴权:由
KeysStore.requireApiKey控制。关闭 → 不鉴权; 开启 → Bearer 必须是「库内启用的 key」或TW2A_API_KEYenv。
环境变量
| 变量 | 默认 | 说明 |
|---|---|---|
TW2A_AUTH_DIR | <dataDir>/auths | 凭证目录(dsh-router 核心统一管,credentials.sqlite SQLite 库) |
TW2A_STATE_FILE | data/state.json | 状态持久化(同目录放 keys.json / combos.json / supplier-config.json) |
TW2A_API_KEY | 空 | /v1 Bearer 鉴权(与库内 key 等效) |
构建
pnpm install
pnpm build # lib/index.js(host) + lib/client.js / lib/client-registry.js(browser)
pnpm typecheck
安装(DSH)
用 dsh CLI 装到 profile(web 是 DSH 插件宿主):
dsh plugin --profile web add dsh-router-core
该命令会在 profile 里 pnpm add,并自动把 dsh-router-core 加入
dsh.profile.bundles(包声明了 dsh.bundle.patch,即 cordis.patch.yml)。
然后重启 dsh web。侧边栏出现「路由系统」入口,打开即面板。
更多供应商:DSH 插件形态的供应商各自发 npm 包,同样
dsh plugin --profile web add <包名>即可;供应商接入与开发见docs/suppliers.md。本地开发版:不用 npm,直接
dependencies加"dsh-router-core": "link:/path/to/dsh-router"指向本地仓库。
前提
- 凭证由 dsh-router 核心统一管(SQLite 库
<dataDir>/auths/credentials.sqlite); - 供应商接入与开发见
docs/suppliers.md; - 重启 DSH 后
/v1/*即生效;面板管理账号、模型与密钥。
致谢
感谢以下项目给的灵感:
- decolua/9router —— 本地 AI 路由网关,面板/组合/连接池/凭证等思路的来源;
- deepseek-ai/deepseek-harness —— DSH「一切皆插件」的宿主框架;
- omdsh-dev/dsh-mnemon —— DSH 插件形态与侧边栏入口的参考。