dsh-router-traework
TRAE SOLO supplier plugin for dsh-router, ported from traework2api. Provides the traework supplier, a free SOLO chat channel, and reports single-account status to dsh-router core.
Install
dsh plugin --profile web add dsh-router-traework
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
<h1 align="center">dsh-router-traework</h1>
<p align="center">dsh-router 的 TRAE SOLO 供应商插件</p>
<p align="center">
<a href="https://www.npmjs.com/package/dsh-router-traework"><img src="https://img.shields.io/npm/v/dsh-router-traework?style=flat-square&logo=npm&label=npm" alt="npm version"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-10b981?style=flat-square" alt="MIT license"></a>
<a href="https://www.npmjs.com/package/@deepseek-ai/dsh?activeTab=versions"><img alt="支持的 DSH 版本:0.2.0+" src="https://img.shields.io/badge/DSH-0.2.0%2B-4d6bfe" /></a>
</p>
<p align="center">
<a href="#快速安装">快速安装</a> ·
<a href="#签到判定">签到判定</a> ·
<a href="https://github.com/CARVIN94/dsh-router#readme">dsh-router 核心</a>
</p>
为 dsh-router 提供 traework 供应商(免费 SOLO 聊天通道)。
单独装它没用——它只是向核心注册一个供应商,面板、账号池、组合回退都在核心里。
本项目是 traework2api 的 DSH 插件版,
上游协议与签到语义参考 wild-work。
快速安装
需要 DSH 0.2.0 及以上(核心已单面 0.2.0,0.1.x 宿主不再支持)。先装核心,再装本插件,然后重启 dsh web:
dsh plugin --profile web add dsh-router-core dsh plugin --profile web add dsh-router-traework
dsh plugin add 会在 profile 里 pnpm add,并自动把声明了 dsh.bundle.patch
的包加入 dsh.profile.bundles(本插件即声明了,即 cordis.patch.yml)。
重启后本插件以 cordis service router.suppliers 向 dsh-router 注册 traework
供应商,面板「供应商」出现 traework 卡片,加账号即用。
本地开发版:不用 npm,直接 dependencies 加
"dsh-router-traework": "link:/path/to/dsh-router-traework" 指向本地仓库。
与核心的分工
本插件只管对单个账号调通上游:SOLO 协议、token 刷新、SSE 转换、签到、积分。
策略全在核心(AccountPool):选号、冷却、禁用、连续错误累计、遍历回退、
响应写入。所以:
chatOnce(uid, req)一次只服务一个账号,不遍历账号、不维护冷却表、不写响应- 失败时返回语义状态(
rate_limit/quota/session_dead/unavailable/
transport / unknown),由核心决定冷却多久、是否禁用、要不要换号
status()只报「现在状态」(凭证 + 积分),冷却/禁用由核心叠加后给面板- 积分只报值,不落盘(持久化归核心
supplier-config.json):启动时用核心
缓存预热,拿不到时报 -1(不是 0),核心保留上次持久化的值
本插件不做自动调度:不挂后台定时器。签到是核心在用户点「签到」时逐个
链接触发的(POST /suppliers/:id/checkin → checkinNow(uid))。曾移植自
traework2api 的每日自动签到 Scheduler 已删除(核心没有定时入口,放着是死代码)。
token 刷新是共享前置:所有打上游的路(chatOnce / 获取模型 / 拉积分 /
签到)都先过一个 freshAuth,临到期或已过期就刷一次并落盘。闲置账号的
accessToken 早就过期了(实测本机三个号全是),哪条路少这一步,那条路就会
静默失效——「获取模型点了没反应」「积分一直是未知」「一直没用过的号签到必
失败」都是这么来的。同一账号的并发刷新会去重:refreshToken 是轮换的,
两个并发刷新互相覆盖可能写坏轮换链。
完整契约见 dsh-router 的 docs/suppliers.md。
获取模型
模型名录取自上游两处,合并后是纯增量(不会从用户手里拿走今天还能用的模型):
1. 远端名录(solo.trae.cn/api/remote/v1/models,按 function 分组)——
厂商给 Trae IDE 模型选择器看的那一份,作为骨架与展示名/窗口来源
2. 详细表(get_detail_param,逐 function 查询)——给出每个 config_name
归属于哪个 function、以及 max_tokens
要点:
- 归属 function 必须回放:上游把可调用名录按 function 拆开,一个模型只有用
列出它的那个 function 才调得动。发错时上游 HTTP 200 但流内 code=4001
(「参数无效」),看起来像请求写错了。2026-10-10 实测:只发 solo_work_lite
时 glm-5.1 / qwen-3.5 / kimi-k2.5 / minimax-m2.7 / qwen-3.6-plus /
glm-5v-turbo / Doubao-Seed-Code 全部 4001,换成各自归属的 function 后
全部正常应答。插件把「模型 → function」记下来,chat 时回放(见
DirectoryFunctions 的顺序即归属优先级)
context_length必须下标,单位是 K(核心comboContextWindow会换算回
token)。以前 fetchModels 恒填 contextWindow: 0,于是核心那条
if (m.contextWindow > 0) 永不成立 → 窗口永远拿不到 → 自动压缩一直跳过。
现在 32+ 个模型都带上真实窗口(context_window_tokens,见下条)
- 窗口取
dev/max的更宽者(issue #11)。上游这两档都实际在用:实测
chat_v3 的 mimo-v2.6-pro 报 {dev:200000, max:981504},step-5-preview
报 {dev:116000, max:1000000}。只读 dev 会把窗口低估,而核心按组合各腿的
最小窗口判可用性 → 长会话被提前判超限。两档都可能缺
(solo_work_lite 的 DeepSeek-V4-Pro 只有 dev;solo_coder 的
DeepSeek-V4-Pro 是 {dev:200000, max:200000}),所以各自先过
positiveNumber 再取 max。同一模型被多个 function 列出时,**function 归属
仍是先命中者**(顺序即优先级,不能改),只有窗口取跨 function 的最宽者
- 远端名录拿不到时,退回主 function 一家的表(改动前的历史行为),不是把
详细表并集原样端出去——并集里有一半是其它 function 独有的内部件
(title_generation / fast_apply / *‑auto 变体…)
模型覆盖与已知边界
- 签到判定(见下)与 chat 是两套上游身份,模型表只服务 chat
- 详细表里不在远端名录、也不在主 function 表里的行 不发布:实测
computer_use_subagent / file_search_agent 直接回 code=3003(不是对话模型)。
但 explore_sub_agent_v2 / summary / glm-5-turbo / aquila / sagitta /
seed-code-pro-0430 实测都能正常出内容,故一并保留——宁多留一个,不误杀可用模型
- 天花板与升级路径:若将来要严格对齐 IDE 名录(只发远端那 32 个),删掉
fetchModels 里「并上主 function 那一家」的那一段即可,一行级改动
- 远端名录的窗口在同一模型多组间可能不一致,取最大值,避免面板窗口随上游
分组顺序变化
签到判定
上游 checkin_credits/* 一律返回 HTTP 200,成败只藏在 body 的 code 里:
code · 含义 · 处理
0 · 成功 · ok(注意:已签到后重复调用也返回 0,是幂等、不加积分)
9004 · 设备身份缺失/不被接受(文案是「订单参数不正确」) · device_missing——不是限流,重试无用;提示重新登录刷新设备身份
9074 · 「当前参与用户太多」 · 账号级稳定拒绝,不是抖动——只重试一次(等 1s)就判失败
9095 · 该设备今日已参与签到 · 见下——不是幂等成功(本机名额被别的账号用掉时,当前账号拿到它却一分没领到)
1001 · token/会话失效 · session_dead(与 chat 401 同义)
status 一共六种:ok / already / disabled / device_used / device_missing / error。
据此定下的判定规则:
- 不能只看 HTTP 状态(一律 200,会误报成功)
- 不能只看
code 0就以为签上了 —— claim 后要**回查
checkin_credits/status 的 checked_in** 才算数
enable缺省按开放处理:只有明确的enable: false才算「今日未开放」。
上游省略该字段时(旧版本/灰度),把缺省读成关闭会把自己唯一该发的那次
claim 拦掉——少签一次的代价远大于多问一次上游
- 不能拿积分当签到凭据 ——
ide_user_ent_usage是所有包的聚合剩余额度,
签到前后可能是同一个数
- 签到前先刷 token:闲置账号的 accessToken 早已过期,不刷必然拿 1001
认证失败(chat 那条路一直有刷,签到以前没有——「一直没用过的号点签到」
就是这么失败的)
关于 9095(证据分级,别当成已实测):上游 ug 族的 NLS 文案是
「该设备今日已参与签到」,口径指向设备;本插件的处理是防御式的——
不论 claim 回什么 code,都以回查 checked_in 为唯一凭据:
- 回查到
checked_in=true→ 成功(code 0那次是本次领到的,否则是本来就有的幂等) - 回查
false且 claim 回9095→ 报独立的device_used并说明原因,
不报 already(把「没领到」说成「已领到」是这里唯一不能犯的错)
- 其余 → 通用 error
本机实测到的是:已领账号(checked_in=true)再 claim 一律回 code 0、与
deviceId 无关(账号级幂等先行),所以 9095 那条分
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::17,最后更新 2026-10-28