Repository navigation
Releases: Abnerluo123/dsh-echelon
Release list
稳定性更新
v1.8.0 — 修「明明有图,模型说看不到」
1.8.0 — 修「明明有图,模型说看不到」
根因一:图片只检查「本轮新增」
上一版的开关「只看本轮的图片」默认开着。贴图那一轮没问题;往下第二、三轮再问「把按钮改成红色」时,选人逻辑认为「这轮没有图」,把请求交给纯文本模型。
而 DSH 是按「被派发的那个成员自己的 inputModalities」决定降级图片的(dsh-llm 的 adapterStream,不是按你选的挡位)。所以那个纯文本模型收到的是占位文字,它回答「我看不到图片」——你看着对话里明明有图。
修复:对话里只要还有一张没被 offload 的图,就要求能看图的成员。这个开关整个删掉,它唯一的效果就是让图片在模型眼里静默消失。
根因二:「强制支持视觉」对声明纯文本的模型无效
成员编辑里可以强制标「支持视觉」,用来纠正不上报的网关。但降级在 DSH 里判定,用的是成员自己的声明,插件改不了。对一个明确声明 ['text'] 的模型强制开视觉,等于把图片送给一个注定收到占位符的线路。
修复:显式声明优先。强制开关只在模型什么都没声明时生效——那正是它有用的场景。
顺带
resolveModel 里 infos.filter(Boolean) 之后仍按原下标读,一个成员解析失败会让后面每个成员错位一格。目前只做 min/max 归约所以数值上看不出影响,已改为索引对齐。
219 项测试。
升级
dsh plugin --profile desktop add dsh-echelon装完重启 dsh 并刷新页面。你配置里的 imageScope: recent 会被忽略,不需要手动改。
v1.7.1 — 预览不再框里套框
1.7.1 — 预览不再框里套框
1. 删掉预览的内层边框
上一版给列表加了边框和底色,结果变成带边框的卡里再套一个带边框的框。现在卡片就是唯一的框,里面只留滚动和最小高度。
2. 预览里的成员数也删了
上一轮说「成员数量别显示」,我只改了挡位卡片,预览里的 · 6 漏了。这次只显示挡位名。
3. 保存按钮略微下移
之前和标题顶端齐平,像要掉出页面上沿。现在比标题中心低 3px。
219 项测试。
升级
dsh plugin --profile desktop add dsh-echelon装完重启 dsh 并刷新页面。
v1.7.0 — 日志落盘、预览按供应商分组、超时下限 3 秒
1.7.0 — 日志落盘、预览按供应商分组、超时下限 3 秒
1. 调用日志写盘,重启不清空
以前只在内存里,程序一退出证据就没了。
- 写到
$DSH_HOME/model-router/request-log.json; - 默认保留 128 条(高级设置 →「保留条数」,20–2000);
- 临时文件 + 重命名写入,不会留半份文件;
- 文件损坏当空日志启动:丢历史可以,丢请求不行。
2. 预览:删标题、按供应商分组、撑满高度
- 删掉「预览:模型选择器会显示」。
- 不再把所有真实模型塞进「其它模型」,任何模式都保留原分组。
- 预览框占满高度,不再是小列表加大片空白。
3. 删「检测」按钮
改成添加成员后自动探测,磁贴直接显示能否使用、能否看图。
4. 超时下限 3 秒(这次真的生效了)
上次只改了后端常量,client.js 里的 clamp 还写着 Math.min(Math.max(value, 5), 900),面板一直把 3 秒改回 5 秒 —— 说两次没生效就是这个原因。现在前后端一致 3–60 秒,并加了测试锁死。
5. 按钮与间距
- 右上角按钮固定叫「保存」。
- tab 下划线、大标题下方、堆叠输入框之间的间距都放宽。
- 删掉「只在内存里」这条已过时的提示。
219 项测试。
升级
dsh plugin --profile desktop add dsh-echelon装完重启 dsh 并刷新页面。
v1.6.1 — 界面收拾干净
1.6.1 — 界面收拾干净
挡位
- 新增挡位插到最前面。以前追加在末尾,列表一长,点完按钮屏幕没变化,看着像失败。
- 挡位可折叠,收起后只剩一行名称。
- 删掉成员数量徽标 —— 只是重复了展开后一眼就看得到的东西。
页面头部
- 删掉标题下面那段说明。
- 保存按钮移到右上角,一个按钮两用:有改动时「保存并重新加载」,没改动时「重新加载」。
- 「放弃修改」和「重新载入」两个按钮删除。
删掉没意义的东西
- 选人策略整个删掉,不让用户改。
- 视觉能力的说明、上下文长度的「支持 128k / 1m」、「0 = 不重试」「0 = 不限制」 —— 全部删除。
数值
- 修掉
undefined/NaN:没设置时摘要会显示成重试次数 undefined · 超时 NaN秒。现在显示「跟随挡位」。 - 上下文长度按
m/k显示:1000000→1m,262144→262k。 - 输入接受
m/k/M/K/ 纯数字 / 小数。k和m改成十进制(1m= 1000000),这样看到什么就输入什么,数值不会被改写。
215 项测试。
升级
dsh plugin --profile desktop add dsh-echelon装完重启 dsh 并刷新页面。
v1.6.0 — 档位不再把思考关掉,超时按秒调
1.6.0 — 档位不再把思考关掉,超时按秒调,提示只留特殊值
1. 档位 high → off(最严重)
有 provider 只上报 off / on 两个值。on 不在别名表里,于是请求 high 时唯一能排序的邻居只剩 off,映射结果就成了 off —— 要求高强度思考,实际把思考关了。
根因:off 被当成"最低档"。它不是很低,它是另一个维度——开关 vs 强度。
现在:
on/enabled/true归到强度侧(on=high同级);- 要强度绝不落到
off,只有off可选时丢弃档位、用模型默认; - 要关闭绝不落到强度档,不能关时同样丢弃,而不是偷偷继续思考。
2. 超时:2–60 秒,全新安装默认 6 秒
DSH 自己会重试一整轮,重试比等待划算:6 秒没进展的线路基本已经掉了,只是慢的线路下一次重试还能答上来。
3. 挡位默认值改成「超时 + 重试」
思考强度在挡位层没有意义(选择器已统一五档),删掉;换成整条链的超时和重试次数。
0 分层:挡位层的 0 = 清掉默认、采用全局;成员层的 0 = 真的不限制 / 不重试。
底层还修了一个真问题:normalizeMember 以前会把全局默认写进每个成员,导致挡位默认永远没有空隙可填。现在未设置就是未设置,优先级在 tierChain 里解析(成员 → 挡位 → 全局)。
4. 提示只保留特殊值
0 = 不重试、0 = 不限制、支持 128k / 1m,其余自解释的一律删除。空提示不再渲染空行。
215 项测试。
升级
dsh plugin --profile desktop add dsh-echelon装完重启 dsh 并刷新页面。
v1.5.1 — 超时真的会停,输入框不再抢键盘
1.5.1 — 超时真的会停,输入框不再抢键盘
三个问题,其中两个是 1.5.0 自己引入或没修干净的。
1. 超时:空包还能骗过去,超时后还在跑
- 空 delta 算成了进展。 1.5.0 把判定从"收到任何 chunk"改成"按类型判定",但只看类型、没看内容,于是网关每 20 毫秒发一个空字符串 delta 就能永久重置计时器。实测:150 毫秒的预算下,63 个空包让这次尝试跑了 1863 毫秒还"成功"了。现在只有携带非空白内容的 chunk 才算进展。
- 超时之后卡在清理上。
iterator.return()在 async generator 上不是"发个信号",它要等那个 generator 当前挂起的操作——而挂起的正是卡住的网络读。所以 8 秒预算会跑出 277 秒:8 秒时已经判定超时,然后卡在清理里。现在超时会先主动取消该成员的请求(每轮一个AbortController),清理本身有 1 秒上限。
2. 输入框在打字过程中纠正你
不是"防小于 5",是每次按键都 clamp:输入 90 会经过 9,而 9 立刻被改写成下限,所以删到个位数时它跳成一个很大的数。
现在:打字过程中只管收数字、不校验;失焦或回车时才规范化(低于下限填下限,高于上限填上限)。
3. 说明文字太长
设置页里的段落级提示全部压成一行。判定规则、误伤边界、取消与清理的细节搬到 README 的「超时是怎么判定的」与「输入框的行为」两节。
211 项测试。
升级
dsh plugin --profile desktop add dsh-echelon装完重启 dsh 并刷新页面。
v1.5.0 — 超时、日志、输入框、热加载
1.5.0 — 超时、日志、输入框、热加载
1. 超时真的会拦了
三个原因叠在一起:
- 看门狗只看"有没有数据",不看"有没有进展"。 网关每隔几百毫秒发一个空包、心跳或计量行,单次等待都没超时,于是这次尝试可以无限挂着,屏幕上什么都没有。现在只有携带内容的 chunk 才算进展:文字、思考、工具调用、块边界、结束。
prepareCall完全在计时之外。 空闲计时从stream()进入才开始,而它在那之前跑(解析能力、刷新令牌、探测目录),没有任何期限。卡在那里就是整轮静默,连日志都没有一条。resolveModelInfo也一样,而且它在写日志之前,所以卡住时日志是空的。
现在三处共用一个预算,超时照样降级到下一个成员。
不会误伤长任务:模型思考时在持续产出 reasoning delta,算进展;模型等待本地命令时,这次模型调用早已以 tool-call 块结束,看门狗根本不在等待。
默认超时 90 秒 → 180 秒,上限 10 分钟 → 15 分钟。因为现在真的会拦,才敢给足正常排队的时间。
2. 日志写清"挡位 → 真实模型"
DeepSeek → trae/deepseek-v4.1-flash 档位 xhigh → max
三种情况:xhigh → max(翻译过)、档位 high(原样)、未发送档位(模型未声明)(丢弃,模型用自己的默认)。
3. 输入框不再自作主张
- 去掉所有数字输入框的上下箭头。 那个箭头会改写打到一半的值:方向键算一次,滚轮划过也算一次。全部改成文本输入 + 数字键盘提示,另加 CSS 兜底。
- 上下文长度/最大输出支持
128k、1m,显示也是短形式,不用数零。k=1024、m=1048576("1M 上下文"指的就是 1,048,576,按十进制算会少 4.8%)。后端同样接受,手改settings.json写"128k"也行。 - 数字字段失焦或回车才提交,打字过程中不再反复重写。
4. 改配置不再需要重启
store.write() 写完刷新了缓存,于是下一次 read() 看到 mtime 一致就直接返回,永远走不到通知订阅者的分支——插件自己保存了配置,却从来不知道。现在写入本身就通知。
通知指纹也从"挡位 id + 成员数"扩成"挡位名 + 顺序 + 成员路由",改名、换成员立刻反映到选择器。
209 项测试。
升级
dsh plugin --profile desktop add dsh-echelon装完重启一次 dsh 并刷新页面(这是最后一次需要重启:此后改设置即时生效)。
v1.4.1 — 开关恢复成有意义的开关
1.4.1 — 开关恢复成有意义的开关
1.4.0 修 API 报错修过头了:为了"只发模型声明过的档位",把选择器一侧的词汇表也改成了上游原样,于是开启映射和关闭映射几乎没有区别,开关形同失效。
这一版把两件事重新分开:
- 模型选择器(「思考强度自动映射」管的地方):开启 = 统一
off/low/middle/high/xhigh,关闭 = 上游原样。 - 成员编辑器的「思考强度」:永远只用该模型上报的档位 —— 那是给单个成员钉死档位,钉一个它不认识的值必然报错。
保留 1.4.0 真正该修的那一条
派发时只发成员声明过的档位,否则不发。 成员没上报档位时,原来"原样转发",理由是"别用猜的值覆盖供应商默认";但 DSH 在发请求之前就校验显式档位,模型没声明的值一律抛 UNSUPPORTED_REASONING_EFFORT。所以在这些成员上,转发不是保持默认,而是保证失败。
现在 mapEffort 的返回值永远是"成员声明过的 id"或 undefined:精确匹配就原样、刻度上能匹配就换成最近的、匹配不到就丢弃。
实际行为
| 映射 | 模型声明 | 选择器显示 | 派发给模型 |
|---|---|---|---|
| 开 | none/low/high/max |
五档 | xhigh → max |
| 开 | 什么都没声明 | 五档 | 不发,用模型默认 |
| 关 | none/low/high/max |
none/low/high/max |
原样 |
| 关 | 什么都没声明 | 只有「跟随会话」 | 原样 |
升级
dsh plugin --profile desktop add dsh-echelon装完重启 dsh 并刷新页面。settings.json 结构未变。
v1.4.0 — 思考档位只发模型真正声明过的
1.4.0 — 思考档位只发模型真正声明过的
修掉一个会让整轮请求失败的档位问题。
症状
模型选择器和成员编辑器里出现模型根本没有上报的档位。例如某个 DeepSeek 模型自己说的是 none / low / high / max,插件却显示 off / low / middle / high / xhigh;选中 xhigh 之后这一轮直接失败。
根因
- 菜单不是上游给的。 开启「思考强度自动映射」时,挡位(虚拟模型)固定上报插件自己的五档,完全不看成员声明了什么。
- 派发时把猜的值原样发了出去。 成员没有上报任何档位时(中转站、免费车道很常见),映射选择"原样转发",理由是"不要用猜的值覆盖供应商默认"。但 DSH 在发请求之前就会校验显式档位:模型没声明的档位一律抛
UNSUPPORTED_REASONING_EFFORT,不裁剪也不做别名映射。所以这不是"保持默认",而是保证失败。
修复
- 菜单只来自上游。 开启映射:取链里第一个真正上报档位的成员,原样展示。关闭映射:取所有成员的交集(关闭时不翻译,交集之外会被成员拒绝)。没有任何成员上报时,这一档不显示推理档位。
- 派发侧只发成员声明过的档位,否则不发。 未知支持、外来名字、刻度上匹配不到,都丢弃档位,让成员用它自己的默认。
mapEffort的返回值永远是"成员声明过的 id"或undefined。 - 新对话默认强度仍是五档偏好,落到挡位时按 rank 就近对齐(
xhigh→max、middle→high),并对齐失败时回落到模型自己的默认值。 - 成员编辑器下拉只列模型上报的档位;旧词汇表下存下的值仍可见,但标注「模型没上报」。
- 文案改成实际行为:映射开关只描述"派发时翻译 / 原样转发"。
升级
dsh plugin --profile desktop add dsh-echelon装完重启 dsh 并刷新页面。settings.json 结构未变,已存的成员档位若模型不支持会在派发时被丢弃,而不是让请求失败。