dsh-router:把 DSH 子智能体接到 sub2api 中继

前言

在 DeepSeek Harness(DSH)里启动子智能体时,常见做法是在 profile 里写死 ANTHROPIC_BASE_URL 和 API key。内置的 Claude Code / Codex provider 在构造时就把 env 解析成静态值;子进程启动时还会按名字擦除带 TOKEN、SECRET 等字样的环境变量。若中继侧要求「每次运行按路由组换一把 relay key」,单靠改配置走不通,需要自己实现 SubagentProvider.start()。

@tokenaissance/dsh-router(维护者 tokenaissance,分类:工作流)把 DSH 的 subagent_router() 接到 sub2api:登录一次把 grant 放进 ctx.credentials,每次开子智能体时按配置的 groupId 取 relay key(内存缓存 5 分钟),连同 sub2api 地址注入子进程,再 spawn claude -p … 走 /v1/messages 到上游订阅账号池。

这是什么

一句话:Route DeepSeek Harness subagents through sub2api — sign in once, fetch a route-group key per run, inject it into the child agent.

数据流可以概括为:

DSH  ──subagent_router()──▶  dsh-router provider
                                  ├─ 取 access token(credentials 里的 grant 记录)
                                  ├─ 取路由组 key(内存缓存,5 分钟)
                                  └─ spawn `claude -p …`
                                        env: ANTHROPIC_BASE_URL=<sub2api>
                                             ANTHROPIC_AUTH_TOKEN=<relay key>

插件以 MIT 许可发布,npm 包名 @tokenaissance/dsh-router,当前版本 0.1.0。类型按 DSH 仓库 0.2.2-alpha.2 编写,与 npm 上 @deepseek-ai/dsh-* 的 0.0.1-rc.1 一代可能存在 API 差异,出树使用时需对齐 peer 版本并实测子智能体调用。

核心功能(v0.1 已核实)

能力 状态
宿主侧 provider(Claude Code / stream-json) ✅ v0.1
凭据落 ctx.credentials(grant 记录)、relay key 仅内存 ✅ v0.1
环境变量令牌引导(开发用) ✅ v0.1
插件页登录(plugins.detail.section + @Remote) ⏳ v0.2
Codex(OPENAI_BASE_URL + OPENAI_API_KEY) ⏳ v0.2
任意 ACP agent ⏳ v0.2

安全相关行为(README 明确说明):登录 grant 与 relay key 分开存放;取不到 key 则抛错、不启动无凭证子进程;stderr 脱敏后落日志;密码与 token 不进 profile、不进 prompt。

sub2api 侧分组有平台类型(如 anthropic、openai 等);未绑定分组的 key 在中继处会 403,因此配置里的 groupId 实际是必填。Claude Code 形态需选接受 /v1/messages 的组,与 Codex 用的组可能不同。

安装与启用

DSH 生态是「一切皆插件」;社区目录在 skillhub.cn,与 DeepSeek / 幻方无官方从属关系。安装前请自行查看源码与许可证:插件以当前 dsh 进程权限运行。

方式一:DSH 仓库内开发(推荐联调)

将包放入 packages/router/dsh-router/,在 DSH 根目录执行:

pnpm install
pnpm run build

或用脚本链接进 DSH 检出:

node scripts/link-into-dsh.mjs /path/to/deepseek-harness
node scripts/link-into-dsh.mjs /path/to/deepseek-harness --link

之后:

cd /path/to/deepseek-harness && pnpm install && pnpm run build
dsh --profile web --dump-config | grep -A5 subagent-router

方式二:外部插件安装

官方命令如下:

dsh plugin install /path/to/dsh-router

安装后通过包内 cordis.patch.yml 插入 subagent-router provider 与 tool-subagent-router 工具。

配置

在 profile 的 cordis.patch.yml 中覆盖 provider 配置,例如:

- id: subagent-router
  config:
    endpoint: https://sub2api.example.com
    groupId: 12
    model: claude-sonnet-4-5
    permissionMode: dontAsk
字段 默认 说明
endpoint — sub2api origin,必须
groupId — 计费/路由分组,必须;可用 GET /api/v1/groups/available 查看
providerName router ctx.subagents 上的名字
command claude 子进程可执行文件
model 继承 固定上游模型
permissionMode dontAsk 透传给子 CLI
keyEnv / baseUrlEnv ANTHROPIC_AUTH_TOKEN / ANTHROPIC_BASE_URL 注入位置
keyTtlMs 5 分钟 relay key 内存缓存时长
preflight true 先 GET /v1/models 验 key 再起子进程
bootstrapTokenEnv — 开发用:存放 access token 的环境变量名

上线前建议向 sub2api 部署方确认:GET /api/v1/settings/public 是否开启 backend mode(会禁用非 admin 面板 API)、登录是否强制验证码、账号是否启用 2FA(v0.1 遇验证码或 2FA 会报错,可改用 token 引导)。

典型用法:三步验证

README 建议顺序不要颠倒:先验 sub2api 与 key,再让 provider 跑通,最后才做 v0.2 的页面登录。

第 1 步:scripts/verify.mjs

与 provider 运行时相同顺序走一遍,并可选发真实请求:

SUB2API_ORIGIN=https://sub2api.example.com \
SUB2API_EMAIL=me@example.com SUB2API_PASSWORD=... \
SUB2API_GROUP=12 \
node scripts/verify.mjs

成功会打印应写入 profile 的配置片段。这步不通,后续配置无效。

第 2 步:bootstrapTokenEnv 跑 subagent_router

export SUB2API_ACCESS_TOKEN=...
- id: subagent-router
  config:
    endpoint: https://sub2api.example.com
    groupId: 12
    bootstrapTokenEnv: SUB2API_ACCESS_TOKEN

SUB2API_ACCESS_TOKEN 可从 verify.mjs --json 输出取得。

第 3 步

v0.2 计划把第 2 步中的 token 引导搬到插件详情页登录流程。

适用场景与注意

适合:已在 sub2api 上划分路由组、希望 DSH 主会话走一套逻辑、子智能体(Claude Code)走中继并按组计费/限流的团队或个人。

注意:

  • v0.1 仅 Claude Code 的 print/stream-json;Codex 与任意 ACP agent 在路线图 v0.2。
  • Node 要求 >=24.9.0;peer 依赖含 @deepseek-ai/cordis、dsh-credentials、dsh-subagent、dsh-subprocess。
  • 与 npm 版 DSH 混用时请钉 peer 并在 pnpm run build 后实测一次 subagent_router。

结尾

dsh-router 解决的是「动态 relay key + sub2api 中继」与 DSH 子进程环境模型之间的错位:用自定义 provider 在每次 start() 取 key 并注入,而不是在 profile 里写死密钥。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye