Skip to content

Releases: Abnerluo123/dsh-echelon

稳定性更新

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 27 Oct 02:41

稳定性更新

v1.8.0 — 修「明明有图,模型说看不到」

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 21:00

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 — 预览不再框里套框

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 19:38

1.7.1 — 预览不再框里套框

1. 删掉预览的内层边框

上一版给列表加了边框和底色,结果变成带边框的卡里再套一个带边框的框。现在卡片就是唯一的框,里面只留滚动和最小高度。

2. 预览里的成员数也删了

上一轮说「成员数量别显示」,我只改了挡位卡片,预览里的 · 6 漏了。这次只显示挡位名。

3. 保存按钮略微下移

之前和标题顶端齐平,像要掉出页面上沿。现在比标题中心低 3px。

219 项测试。

升级

dsh plugin --profile desktop add dsh-echelon

装完重启 dsh 并刷新页面。

v1.7.0 — 日志落盘、预览按供应商分组、超时下限 3 秒

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 19:31

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 — 界面收拾干净

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 18:59

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 — 档位不再把思考关掉,超时按秒调

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 18:36

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 — 超时真的会停,输入框不再抢键盘

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 18:07

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 — 超时、日志、输入框、热加载

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 17:44

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 — 开关恢复成有意义的开关

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 17:11

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 — 思考档位只发模型真正声明过的

Choose a tag to compare

@Abnerluo123 Abnerluo123 released this 26 Oct 16:23

1.4.0 — 思考档位只发模型真正声明过的

修掉一个会让整轮请求失败的档位问题。

症状

模型选择器和成员编辑器里出现模型根本没有上报的档位。例如某个 DeepSeek 模型自己说的是 none / low / high / max,插件却显示 off / low / middle / high / xhigh;选中 xhigh 之后这一轮直接失败。

根因

  1. 菜单不是上游给的。 开启「思考强度自动映射」时,挡位(虚拟模型)固定上报插件自己的五档,完全不看成员声明了什么。
  2. 派发时把猜的值原样发了出去。 成员没有上报任何档位时(中转站、免费车道很常见),映射选择"原样转发",理由是"不要用猜的值覆盖供应商默认"。但 DSH 在发请求之前就会校验显式档位:模型没声明的档位一律抛 UNSUPPORTED_REASONING_EFFORT,不裁剪也不做别名映射。所以这不是"保持默认",而是保证失败。

修复

  • 菜单只来自上游。 开启映射:取链里第一个真正上报档位的成员,原样展示。关闭映射:取所有成员的交集(关闭时不翻译,交集之外会被成员拒绝)。没有任何成员上报时,这一档不显示推理档位。
  • 派发侧只发成员声明过的档位,否则不发。 未知支持、外来名字、刻度上匹配不到,都丢弃档位,让成员用它自己的默认。mapEffort 的返回值永远是"成员声明过的 id"或 undefined。
  • 新对话默认强度仍是五档偏好,落到挡位时按 rank 就近对齐(xhigh → max、middle → high),并对齐失败时回落到模型自己的默认值。
  • 成员编辑器下拉只列模型上报的档位;旧词汇表下存下的值仍可见,但标注「模型没上报」。
  • 文案改成实际行为:映射开关只描述"派发时翻译 / 原样转发"。

升级

dsh plugin --profile desktop add dsh-echelon

装完重启 dsh 并刷新页面。settings.json 结构未变,已存的成员档位若模型不支持会在派发时被丢弃,而不是让请求失败。