← 返回条目

Ebony-Vinyl/dsh-our-free-model · 使用说明

中文版:依据官方 README 翻译整理,保留原有结构与命令

dsh-our-free-model

简体中文 | English

Trendshift JavaScript 周榜第 1 · 2026-10-05 至 2026-10-11 · 更新中,截至 2026-10-11

你只需在 dsh 里装上这个插件,无需登录、注册、填 API Key 或任何其它操作,
就能用上包括 DeepSeek V4.1 Flash、Kimi K3 在内的前沿模型——完全免费,不限量。
*All you do is install this plugin in dsh: no login, no sign-up, no API key, nothing
else. The frontier models are just there — DeepSeek V4.1 Flash, Kimi K3 and the rest.
Free, with no usage cap.*
模型清单跟随上游刷新,可用性由你自己这台机器的网络出口实测得出,
思考强度下发的是真实预算而不是提示词,另附一个 OpenAI 兼容的本地转发端口。
纯插件挂载:不改内核、无构建步骤、零依赖。

交流群

QQ 群:1109211487(AI技术交流学习7群)

扫码或搜索群号加入群聊,一起交流插件使用心得、反馈问题与分享玩法。


亮点

你会看到什么

输入框的模型选择器

分组内容
Our Free Model当前网络出口可直接使用的模型
Our Free Model · region-limited上游对该地区不放行的模型,保留可见但单独隔离

被判定为「已声明但不路由」的模型不出现在任何分组中——它们仅在设置页的「不在选择器中」分组保留记录,

附带拒因与探测时间;后续探测重新通过后自动回到选择器。

设置页 设置 → Our Free Model,包含七个分区:

独立本地服务(开发中)

仓库现在提供两个入口:下文安装的是 DSH 插件;packages/standalone 是

无需安装 DSH 的独立本地服务。从完整源码仓库运行:

npm run start:standalone

独立服务默认使用 ~/.our-free-model 和端口 18900,拥有自己的 API Key,

不读取插件数据。支持匿名/Kilo、EAC 和十个账号渠道,提供

Chat Completions、Responses API,以及独立网页管理(模型、统计、渠道、EAC、设置、API Key)。

启动后打开终端打印的一次性管理链接即可使用;账号在独立页面登录,也可手动导入插件账号备份。

启动、参数与验证见 独立服务说明。

独立服务的安装制品与 Release 尚未发布。

安装

⚠️ 不要通过 npm 安装本插件。
npm 上的 dsh-our-free-model 包不是本仓库发布的。它由第三方打包,内容与本仓库
不一致:index.js、client.js 被改动,并额外包含本仓库从未有过的
src/channel-visibility.js。装到它得不到本项目审核过的构建,也拿不到本仓库的签名
清单校验与应用内升级。
请只按本文档下方的方式安装:使用本仓库的 Release 发布包,或本地源码目录。
其它渠道出现的同名包一律以本仓库为准。

命令行(纯 dsh web)

dsh plugin --profile web add /绝对路径/dsh-our-free-model

安装完成后重启应用一次。--profile 填写实际使用的 profile 名称。

DSHEAC AIO / 桌面端:请先阅读本节

部分 DSHEAC AIO / 旧版桌面整合包在启动 web 服务之前会执行 profile 闸门,

限制 profile 中的符号链接或目录 junction。若当前宿主包含该检查,可能报错:

PROFILE_UPGRADE_REQUIRED: offline dependency migration is not yet available

遇到该闸门时,不要使用 link: 依赖或 junction;使用应用内插件管理器,

或下方的本地 tarball 安装。不同宿主的限制以自身日志和安装机制为准。

以真实目录手工安装时,使用可信源码打出的本地 tarball:

  1. 创建 /profiles//vendor/,在审核过的本仓库目录运行 npm pack --ignore-scripts --pack-destination "/profiles//vendor",或将本仓库正式发布的同版本 tarball 放入该目录。本地打包不执行 npm 发布。
  2. 在 profile 的 package.json 的 dependencies 中加入 "dsh-our-free-model": "file:./vendor/dsh-our-free-model-2.5.9.tgz"。文件名版本跟随仓库 package.json,不要改成同名 npm 注册表版本;再通过宿主的安装流程解析依赖。
  3. 在 dsh.profile.bundles 末尾追加 "dsh-our-free-model"。

包管理器拥有这份安装的字节时,同时将 bundle config 或插件 settings.json 的 distribution 设为 managed,由包管理器统一更新;应用内升级、公告 feed 与热重载会停用,模型功能保留。以后更新时替换可信 tarball 并同步依赖路径,避免包管理器按旧锁文件恢复旧版本。

若手工复制发布文件,必须复制完整包,包括 adapter/、src/、locale/ 和 vendor/channel-pack/ 下的 pack.js、WASM、LICENSE、NOTICE;只复制入口脚本会导致渠道加载失败。

不要再向 cordis.patch.yml 添加条目。被 dsh.profile.bundles 引用的包,其自带的

patch 层会自动生效;两处同时注册将报错 duplicate loader entry id: our-free-model。

整合包(托管安装)

插件由整合包(EAC 整合包、Mojobox 等)安装时,更新时机与文件字节由安装方控制:

安装时将 bundle config 设为 distribution: 'managed'(或向 settings.json 写入

同一字段),插件的应用内升级、公告 feed 与热重载即全部停用——两个写入方同时操作

同一安装目录只会导致目录损坏;模型 lane 不受影响。相关验收见

scripts/offline-test.mjs;目录就绪记录(manifest 0.15 / 出处 / 许可 / 完整性)

位于 catalog/ 下。

启动桌面端前的自检

可直接调用桌面端自身的闸门代码进行自检:

node -e "
const g = require('/sidecar/dist/lib/profile-upgrade.js');
const app = '', profile = '/profiles/';
console.log(g.planProfileUpgrade(app, profile));
g.assertProfileStartup(app, profile);
console.log('startup gate: PASS');
"

预期输出为 status: 'compatible'、mismatches 为空数组,随后输出 PASS。

若仅需确认 bundle 组合是否正确而不启动界面:

DSH_HOME= dsh --profile  --dump-config | grep our-free-model

应当只出现一个 id: our-free-model。

安装失败:ERR_PNPM_VIRTUAL_STORE_DIR_MAX_LENGTH_DIFF

该问题源于目标 profile 的 pnpm 状态,与插件仓库无关(报错发生在下载插件之前):profile 中已有的

node_modules 由旧版 pnpm 生成,dsh 更新后内置的 pnpm 版本发生变化,pnpm 拒绝在旧参数上继续安装。

关闭 dsh,删除该 profile 的 node_modules 与 pnpm-lock.yaml 使其重建,然后重新安装:

rd /s /q "%DSH_HOME%\profiles\web\node_modules"
del "%DSH_HOME%\profiles\web\pnpm-lock.yaml"

同时出现的 Ignoring broken lockfile 警告会随重建一同消失。

安装失败:git ls-remote "git+ssh://git@github.com/..."(插件市场自动安装)

插件市场(dsh-plugin-hub)对 git 源的自动安装会把 GitHub 地址交给 pnpm 解析,pnpm 再调用本机

git 执行 git ls-remote。若本机 git 配置了 insteadOf 重写(常见于把 https 改写为 ssh 的

url."git+ssh://git@github.com/".insteadOf 规则),或 SSH 密钥未配置,这一步会在下载任何插件

文件之前失败。处理方式二选一:

git ls-remote https://github.com/Ebony-Vinyl/dsh-our-free-model.git 能成功;

安装失败:profile "desktop" is managed exclusively by the Electron application

这是宿主自身的保护,不是插件问题:桌面端(Electron)的 profile 只允许桌面应用自己管理,

命令行 dsh plugin add 无法写入。请在桌面端的插件管理器(设置 → 插件)里完成安装或升级;

命令行安装仅适用于纯 web profile(dsh web)。

桌面安装包(macOS,社区构建)

DSH 插件本体无需构建、解压即用;桌面安装包(Our Free Model 桌面壳)官方目前只发布 Windows 版。macOS 版为社区构建:源码改动见 PR #421,可逐行审计;预打好的 Apple Silicon(arm64)包以社区 Release 的版本和校验值为准,也可以自己从源码构建(macOS 上执行 npm --prefix packages/desktop run build,完整流水线见 .github/workflows/build-macos.yml)。

下载后建议先核对校验和(SHA256 见 PR / Release):

shasum -a 256 ~/Downloads/Our.Free.Model__aarch64.dmg

安装后提示「已损坏」或打不开?

社区构建没有 Apple Developer 账号签名与公证,Gatekeeper 会拦截首次启动——这不是文件真的损坏,以下几种方式任选其一:

  1. 右键打开:在访达中按住 Control 点按应用图标,选择「打开」,在弹窗中再次点按「打开」。
  2. 清除隔离属性(终端):
   xattr -cr /Applications/Our\ Free\ Model.app
  1. 仍提示损坏时,用 sudo 清除隔离属性(较新 macOS 对未签名应用校验更严):
   sudo xattr -rd com.apple.quarantine "/Applications/Our Free Model.app"
  1. 在系统设置中放行:打开「系统设置 → 隐私与安全性」,若出现「仍要打开」按钮,点按确认。

几点说明:

使用说明

选择模型:打开输入框的模型选择器,选择 Our Free Model 分组下的任意模型。选择结果按会话持久化。

调整思考强度:同一菜单中的 Effort。声明了思考档位的模型给出它自己的档位(如 Off / Low /

High / Max),选中值按原值下发;其余模型给 Light / Balanced / Deep 三档,档位越高思考占用的

输出预算越多,上限为强制下发,因此档位之间存在可测量的差异。思考与可见回答共享同一输出额度,

因此思考不可关闭的模型会将三档整体上移(设置 → Our Free Model 的模型卡上标注了每档的

实际数值,声明档位的模型则标注档位名)。若回答被截断,可切换至更高档,或调高设置中的

单次输出上限。

供本机其它工具调用:设置 → Our Free Model → 本地转发,启用后复制 base URL 并生成 Key。支持:

端口被占用时插件不会静默失效:先在同一端口重试数轮(刚关闭的监听、刚删除的

portproxy 规则通常在数百毫秒内释放),仍被占用则顺延至下一个可用端口,并在设置页标注

"请求的 18899 不可用,实际监听 18900",落盘的也是该实际端口。Windows 上最常见的占用

来源是一条 netsh interface portproxy 规则(由 IP Helper 服务承载):其对 0.0.0.0 的

监听会导致回环绑定直接返回 EACCES(区别于 EADDRINUSE)。netsh interface portproxy show all 可列出规则,netsh interface portproxy reset 可清除规则。

转发端点为全流式:除 data: 帧外,思考期间的静默由周期性写出的 SSE 注释帧

(以 : 开头)填充,客户端的 idle 超时因此不会将"上游仍在推理"误判为"连接已断开"。思考内容按

reasoning、reasoning_content、reasoning_text 三个字段识别——同一段思考若被上游同时

写入两个字段只计一次——reasoning_details 数组同样识别。上游本身不流式输出思考的模型,此处

也不会产生思考帧,详见「已知边界」。

供同一网络中的其它设备使用:同一面板下方还提供"局域网访问"。该功能默认关闭;启用后中继绑定一个可路由地址(默认 0.0.0.0),并要求使用独立的局域网 Key——与上述本机 Key 互不通用,因此任一泄露只需轮换对应一侧,本机已配置的工具不受影响。中继将请求原样转发至本机监听,模型清单、流式行为与错误语义与本机完全一致。端口填 0 表示自动分配(本机 18899 常已被占用或被端口代理占用),启用后面板会显示实际端口与局域网地址。局域网地址按本机网卡实时读取:面板在开启期间每 15 秒重读一次,切换到别的网络后不必重开面板。同一台机器常同时持有多张网卡上的私网地址——路由器分配的 192.168.x.y,以及虚拟交换机(WSL/Hyper-V/Docker)、VPN 或隧道适配器上的地址——面板把物理网卡的地址排在前面并作为可直接复制的那一条,其余地址列在其下;中继绑定的是所有接口,但某个地址能否被同网段的另一台机器拨通,取决于该地址所属的那张网卡。启用期间,任何能够访问该主机的用户均可使用此 Key 消耗本机的免费额度,因此请仅在可信网络中启用,必要时通过防火墙限制来源网段。

重新核对地区:点击"重新探测可用性",将按当前出口重新执行探测。切换 VPN 状态后再执行一次,

地区受限模型会在两个分组之间自动迁移。

接收公告:全自动。仓库维护者推送新公告后,运行中的插件在一个轮询周期内(默认

30 分钟,也可在公告中心点击"检查新公告"立即拉取)收到通知:普通公告弹出 toast,

urgent 级别直接触发全屏弹窗,两者均会进入公告中心并保留未读标记。如需同时接收

系统级通知,在公告中心点击"开启系统通知"。

升级插件:设置 → Our Free Model → 插件升级 → 检查更新 → 立即升级。全流程

在应用内完成(下载 → 校验 → 备份 → 替换 → 热重载),无需重新安装,也无需

重启应用。升级失败会自动回滚至上一版本并给出失败原因。

Gemini 与 Cline 的代理连接

Gemini 登录需要访问 accounts.google.com、oauth2.googleapis.com、www.googleapis.com,模型请求还需访问 Google Code Assist 服务。浏览器能打开授权页,只说明浏览器的网络可用,插件仍需能访问这些端点。

Gemini 的登录、续期、项目探测和推理,以及 Cline 的登录、续期和推理,共用逐请求代理:优先使用已运行的插件出口代理,其次读取 HTTP_PROXY / HTTPS_PROXY / ALL_PROXY,最后在 Windows 读取当前用户的手动系统代理;没有代理时直连。环境代理遵守 NO_PROXY,系统代理遵守 ProxyOverride;回环请求不自动使用代理。无需为这两条渠道设置 NODE_USE_ENV_PROXY,也不会改动宿主的全局代理。

Windows 自动检测只支持手动代理,不执行 PAC 自动配置脚本;系统设置最多缓存 30 秒。仅配置 PAC 时,请改用插件出口或环境代理。网络失败会显示所选路径及 UND_ERR_CONNECT_TIMEOUT、ENOTFOUND 等底层错误码;代理连接失败不会自动重试直连。浏览器回调未到达的授权超时仍需检查本机回调地址和端口是否可达。

聚合渠道、省 Token、路由与本地网关

聚合渠道:自带 Key 的 76 家提供商

设置页的聚合渠道一页把第三方端点接进同一条模型清单。提供商注册表内置 76 家(src/providers/registry.json,分类为 free | free-tier | apikey | oauth | local),包括 NVIDIA NIM、OpenRouter、Groq、Cerebras、SambaNova、Gemini、DeepSeek、Mistral、Together、Fireworks、SiliconFlow、Nebius、Chutes、Hugging Face、Cloudflare、Z.ai、Kimi、MiniMax、QwenCloud/Alibaba、Bedrock、Vertex、Vercel AI Gateway、Azure OpenAI、FleetRelay Gateway,以及本机、无需账号的 Ollama、LM Studio、llama.cpp。注册表数据来自 free-claude-code 的提供商目录、9router 的提供商注册表,以及本项目新增的自定义中转。FleetRelay Gateway 当前公开 deepseek-v4.1-flash-free 与 gpt-6-astra;其第三方 T1 候选池尚未获分发授权,因此保持禁用。

写入 Key(本机免账号的提供商不需要)后,该提供商的每个模型以 provider/model 成为清单行:在选择器里可选,也可经本地网关调用。三种线协议按提供商各自声明:OpenAI Chat Completions、OpenAI Responses 与 Anthropic Messages(后两者用于只提供这两种协议的上游)。

Key 只写入插件自己的 0600 settings.json,接口永不回显——页面只显示 hasKey 与 …abcd 指纹;字段缺省表示保留已存 Key,空字符串表示清除。每家提供商提供:启用/停用、测试、发现模型、Base URL 覆盖(Azure / Cloudflare / Vertex 没有可用默认值,必须覆盖)、模型清单覆盖与移除。测试按钮是列表探测:它用提供商的模型列表验证 Key,不花一次生成;提供商声明没有列表接口时,按钮如实说明。OAuth 与 ADC(Google ADC)认证的提供商照常列出并标注「不可驱动」——本车道无法替它们完成交互式登录或云侧凭据流程。OpenCode 的免密免费池不在此注册表内:它要求每请求一枚铸造形状的会话 id、v2 客户端 User-Agent 与一组官方工具声明,本车道的通用传输没有地方承载这些,硬列进来只会是一个点不通的选择器行——这 10 个模型本来就由本插件自己的免费车道原生提供(见「免费车道」)。

省 Token:工具输出压缩、提示词瘦身与本地应答

工具输出压缩(RTK) 在请求发出之前就地重写 tool_result / role:"tool" 内容:git diff、git status、git log、grep、find、ls、tree、构建与包管理器日志、带行号的文件转储、Cursor 搜索清单,以及成串重复的日志行。实测:40 KB 的 git diff 移除 90% 的字节,模型仍就这份 diff 作出了回答。安全规则:报错的工具结果永不触碰,小于尺寸下限的内容不碰,替换结果永不大于原文,过滤器抛错时原样放行,且整条管线幂等。该压缩对全部车道生效(含本地网关),默认开启。

提示词瘦身 有两族可选项与档位:caveman(电报体回复:off/lite/full/ultra/wenyan-lite/wenyan/wenyan-ultra)与 ponytail(YAGNI 最小实现:off/lite/full/ultra)。它们改变助手的说话方式,因此所有档位默认 off。注入是幂等的、按线协议进行的(chat 的 system 消息、Anthropic 的 system(含块数组形式,且插在最后一个 cache_control 之前)、Responses 的 instructions/input 项),并且可以撤销。

节省统计 显示压缩前字节 → 压缩后字节、节省字节、节省比例、压缩块数与统计调用数——数据取自用量图表所用的同一批统计行。

五个本地应答(自 free-claude-code 移植,各自独立开关,默认全开)不调用任何提供商:额度探测(max_tokens:1 + "quota" → Quota check passed.)、shell 命令前缀识别(` + Command: → 前缀,检测到命令注入时拒绝)、会话标题生成(→ Conversation)、建议模式(→ 空字符串)与文件路径提取(→ ` 块)。它们由本地网关在进程内直接应答。

路由:命名降级链(combo)

一条命名、有序的模型 id 列表,跨全部车道,以 combo: 出现在选择器与网关上,如同一个虚拟模型。两种策略:fallback(固定从链首开始)与 round-robin(轮换起点,连续 N 轮粘滞)。链会逐个链接尝试直到有一个产出输出;在任何正文增量之前失败的链接被整段丢弃,因此切换对调用方不可见。思考增量刻意不算正文——「想了一分钟,然后撞上配额墙」正是最值得降级的场景。一旦已有正文增量交付,之后的失败按正常方式结束该回合(单模型检查点恢复仍先获得它的续写尝试)。链路容量取交集(只有每个链接都支持视觉,链才声明视觉;上下文窗口取最小值),全部链接当前不可用的链会被原样保存并标注为不可用,而不是被静默丢弃。

本地网关:原生 Anthropic 接口与接入配方

新增端点 POST /v1/messages(流式与非流式,message_start / content_block_* / message_delta / message_stop 正确成帧,含 thinking 块、tool_use 块、真实 stop_reason,以及响应头发出之后才失败时的流内 error 事件)与 POST /v1/messages/count_tokens(本地估算——插件不含 tokenizer)。Claude Code 与 Anthropic 各 SDK 因此可以直接指向本插件。原有的 /v1/chat/completions 与 /v1/responses 不变,/v1/models 现在广播全部车道,含聚合行与链路。网关页新增「接入客户端」分区,按实际绑定的端口与真实要求的密钥生成可复制的配方:Claude Code 环境变量、Codex config.toml、OpenAI SDK、Anthropic SDK、curl,以及中继开启时的局域网版本。

顺带修掉一个假成功:一轮只产出了一个调用方从未声明的工具调用时,过去会以干净的空成功收尾;现在会如实报告发生了什么——压缩器自己追加的 [full diff: rtk git diff --no-compact] 提示就可能让模型去调一个调用方没有的工具。

实现结构

index.js Host 半身:适配器注册、清单与可用性探测、设置/用量存储、
 webServer 路由、转发端口生命周期、公告/升级/热重载接线
adapter/ 内核接缝:全包唯一允许 import @deepseek-ai/* 的位置
 (kernel.js:attribution User-Agent,失败降级为字面量)
src/adapter.js 结构性 LlmAdapter:providerInfo、listModels、resolveModel、
 prepareCall、stream、providerRetryPolicy
src/upstream.js 网关身份:凭据、session/request id 铸造、工具指纹、按线协议选端点
src/stream.js 三种线协议解码(chat / messages / responses)归一为 harness StreamChunk,
 并做不相交的 token 计数
src/messages.js harness 消息 -> 各线协议形态,外加工具调用配对修复
src/effort.js 思考档位 -> 输出预算
src/forward.js 独立的 OpenAI 兼容监听器(另含 Anthropic Messages 端点)
src/providers/registry.json 聚合车道注册表:76 家提供商的分类、认证、线协议与端点
src/providers/index.js 注册表读取与 provider/model 复合 id 解析
src/aggregate.js 聚合车道:清单行、凭据解析、Key 脱敏、列表探测、按线协议发送
src/anthropic.js /v1/messages 的 Anthropic Messages 编解码与本地 token 估算
src/token-saver/index.js 压缩管线:提示词注入 -> 工具输出压缩,按字节留痕、失败开放
src/token-saver/inject.js chat / messages / responses 三线的幂等注入与撤销
src/token-saver/prompts.js caveman / ponytail 两族提示词与档位
src/token-saver/rtk/ 工具输出过滤器:git diff/status/log、grep、find、ls、tree、
 构建日志、编号转储、搜索清单、重复日志行
src/local-optimize.js 五个本地应答:额度探测、命令前缀、会话标题、建议模式、文件路径
src/combos.js 降级链:虚拟清单行、两种策略、容量取交集
src/route/classify.js 全车道统一的失败词汇与冷却策略
src/trust.js 插件路由的请求信任围栏(connection 服务桥 + 结构化围栏)
src/push.js SSE 推送枢纽:公告到达、更新可用、升级完成
src/feed.js 远程公告 feed:多源拉取、校验、缓存、到达检测
src/updater.js 应用内升级:清单校验、SHA-256 分级校验、备份、原子替换、回滚
src/reload.js 自热重载:镜像内核 HMR 的缓存清除 + 重导入 + 重注册 + 回滚序列
client.js 浏览器半身:手写 ModuleLoader bundle,无构建步骤

几个值得了解的架构决定:

一个适配器,两条 provider 路由。 harness 的模型选择器严格按 provider 路由分组,

而清单的线格式中并不存在 group / tag / badge 字段。因此要呈现独立的 region-limited

标题,唯一方式是再注册一条路由;又由于客户端会丢弃空分组,一旦地区限制解除,

两个分组会自动合并为一个。

以结构化方式实现适配器,不 import @deepseek-ai/dsh-llm。 内核从不执行 instanceof

检查,因此鸭子类型即可满足。这使插件不必将依赖固定在特定内核版本上,也是同一份代码能同时

运行于 0.1.5 与 0.1.7 的原因。

使用自有 JSON 存储,不接入 settings seam。 settings 注册 API 在两版内核间不一致;

私有 JSON 存储行为一致,且转发 Key 存放于 0600 权限文件中,不进入任何共享设置文档。

Token 压缩跑在唯一收口上,且失败开放。 提示词注入与工具输出压缩在 payload 完成全部

改写之后执行——指纹改名、档位补丁、密封车道的节奏提示都已落定——收口在 payloadFor():

适配器自己的派发与本地网关(它同样经适配器发起)都从这唯一一处经过,因此每条车道、每一段

恢复请求都同样压缩。每一步都失败开放:压缩器抛错就跳过,过滤器抛错就原样放行,形态不认识

就不动——一个请求绝不能因为一个「本来是为了让它更便宜」的环节而失败。

combo 是一条虚拟清单行,降级在适配器里解析。 链路以 channel:'combo' 加一串真实模型

id 并入合并后的清单,因此选择器照常广播它、本地网关照常按名调用它;链的展开与推进判定发生

在适配器的 runStream() 内,于是两个调用方都不必知道降级这件事。

思考强度:档位菜单与预算阶梯

两类模型,两种控制。

声明了思考档位的模型(清单里的 reasoning_options 给出 effort.values)走档位菜单:

选中的档位按原值下发到上游的 reasoning_effort 字段,与 EAC / Kilo 渠道同款。这是 2026-10-17

的复测结论——早期(2026-09-24)该车道确实忽略这个字段,但现在它会校验:发一个集合外的

取值直接回 400 invalid_value 并列出可接受集合(none|minimal|low|medium|high|xhigh|max),

而思考量随档位真实变化(deepseek-v4.1-flash-free 三次采样中位数:none 0 / low 793 /

high 700 / xhigh 1405 / max 1906)。因此菜单只列出该模型自己声明过的档位;模型没声明

「关闭」档(如 GLM 5.3 Flash,其 none 实测关不掉思考)就不提供 Off 档。

没有档位菜单的模型(清单只给 toggle 或 budget_tokens,或压根没有 reasoning_options)

保留预算阶梯:思考强度实现为硬性输出 token 上限,该上限确实产生约束——留痕的思考 token

随档位单调上升。对一个上游表达不了档位的模型,编一档等于谎报能力,所以这里不编。

模型的窗口与输出上限按 9router / models.dev 的口径取(limit.context / limit.output、

modalities.input);上游清单本身只公布 id,不含任何能力字段。

三个实际消耗过调试时间的内核行为

此处列出是因为编写 provider 插件时通常会遇到:

providerRetryPolicy() 会被原样保存并使用。 两版内核均不解析其返回值,而退避调度器读取的是

顶层的 initialDelayMs / maxDelayMs / jitterRatio。将这三项嵌套在 backoff:{} 中,

调度器读到 undefined,于是 undefined \* 2ⁿ = NaN,而持久会话日志会直接拒绝非有限数值——

一个本可恢复的瞬时故障因此导致整轮对话报废。应返回已解析完毕的扁平策略。

一次被中断的工具调用会永久污染该会话。 缺少对应结果的工具调用在重放时,上游返回

400 invalid_request_error,此后该会话中的每一次请求都会失败。本插件在发送前修复配对,

三种线协议共用同一处修复逻辑。

**未在 inject 中声明的服务,属性直读会抛错(与返回 undefined 不同);而 ctx.get() 在服务

"尚未被 provide 出来"时返回 undefined。** 这两条本轮各自触发过一次问题:将 inject 缩减为仅剩

llm 之后,typeof ctx.interval === 'function' 直接抛出 cannot get property "timer" without inject(ctx.interval 是 timer 服务上的 mixin),插件在所有 composition 中

均不再激活;改用 ctx.get('webServer') 后返回 undefined——原因不在于缺少 web

server,而在于插件先于 web 半身加载——导致设置页路由全部未注册。正确做法是

ctx.inject(deps, callback):为所需服务开启一条独立的 fiber 使其待命,

避免在加载瞬间做一次性判断。

为什么按 body 的形状而不是 Content-Type 读响应

该车道会在高负载下以 200 + application/json 返回完整的 SSE 帧序列。旧实现依赖 header,

于是 await response.text() 将整条流读成字符串、JSON.parse 失败、整轮报废——而该

错误对象携带 status: 200,还会使可用性探测将完全可用的模型判为"不可路由",

使其在下拉框中消失一轮。当前实现先嗅探首块(≤4 KB)按形状分流,再将已读取的字节

重新注入流中,实时性不受影响;src/http.js 的 sniffBody 为唯一判据。

为什么速度那一栏会显示 —

早期版本曾为一条实际仅 ~40 tok/s 的车道报告出 2 941 tok/s。问题不在网关——直连

读包的探针显示 64 个帧跨越 5.6 秒,确为增量投递——而在于分子与分母度量的不是同一段

时间:一次调用计费 422 个输出 token,其中 291 个是未流出任何帧的 reasoning token,

它们在第一个可见 token 之前即已生成完毕,而窗口起点正是该 token。以整段

以整段 completion 耗时除以答案文本落地所用秒数,无法反映解码速度。

因此当前实现仅在"能够容纳分子的那段时间"内输出速率:windowTokens() 将未流出的

reasoning token 从分子中剔除,decodeWindow() 拒绝过短以至于无法计时的窗口以及不真实的

高速率,看板与模型表均改为 Σtoken / Σ秒,不再对各次速率取平均——曾有一个 1 ms

的窗口将 26 次调用的均值抬高了三个数量级。因此答案集中在一两个大帧中落地的模型,

不具备可测量的输出速度,该栏显示 —。

长思考截断后的自动恢复(issue #12)

所有模型默认启用一次有界恢复,Chat Completions、Messages、Responses 三种上游协议

共用该行为。触发条件为:首段仅有非空思考、无正文且无工具调用,且上游在未发送正常

结束帧的情况下直接关闭流;或上游发送了正常 stop 收尾、但同样只有思考而无正文——宿主会将

此类「空停」回合判定为空响应,恢复流程会继续请求一次正文。以下情况不触发恢复:用户取消、

已输出正文或工具调用的正常结束、达到输出上限、明确的上游错误。

插件将已收到的思考作为检查点文本,与原始输入一起发起新请求,要求直接输出整理后的回答。

该机制基于检查点重新发起请求,与上游原生 resume 无关,也不会重放已显示的思考内容。恢复段禁用工具调用;已输出

正文或已开始调用工具的截断回合不执行恢复,以避免内容重复或工具重复执行。

为避免重复长思考,恢复提示要求结论优先、最多 800 词;此为提示层面的约束(非硬性 token

限制),模型可能不遵守。恢复属于降级回答,原始请求中的长篇或逐步分析可能被简化。

每个逻辑回合最多两次物理请求:原始请求加一次恢复。默认总时限 900 秒(15 分钟),恢复段最多

300 秒,且受剩余总时长约束;恢复输出上限 8192 tokens,并继续受用户与模型的上限

约束。首段已知的输出 tokens 会从原始预算中扣除,恢复预算不足 512 tokens 时不发起恢复。

检查点最多 131072 字符,且必须通过基于文本字节的保守上下文余量估算;该估算不计算图片

token,不等同于精确的 tokenizer 校验。超出限制即停止恢复,不会无限续接。恢复必须正常结束且

产生非空白正文方为成功;失败返回 STREAM_CUT,宿主不会将该回合整轮重发,用户取消

则保持 aborted / ABORTED。

可通过本机 settings.json 的 streamRecovery: false 关闭恢复;也可通过对象的 enabled

开关及数值限制收窄边界,数值只能低于或等于默认上限。默认不限制模型名单。

用量看板将物理请求与逻辑回合分开统计。上游请求数与请求失败数按实际发出的请求次数计数;

对话回合数、回合失败数与已恢复数按一次适配器调用的最终结果计数。例如首段中断、

续写成功会记为 2 次上游请求、1 次请求失败,同时记为 1 个对话回合、0 次回合失败、

1 次已恢复。每段样本仍包含恢复关联、段序号与 noUsage 等标记;通过 recoveryId

关联各段的 noUsage 以判断缺失情况。最终上报宿主的 usage 仅汇总上游实际报告的已知值;

缺少某段 usage 时,该值不等于整轮完整 token 总量。思考检查点不写入统计文件。

升级前的旧统计仅包含物理请求记录,迁移后展示的回合数与失败数为基于这些记录的推算值,

看板会明确标注;升级后的回合按最终结果精确记录。

请求数、回合数与 Token 总量为累计值;速度、首帧延迟与热力图使用本机保留的历史窗口。

已在一次真实 MiMo V2.6 Flash · Deep 请求中恢复成功;此前一次恢复曾在 480 秒

截止时失败。这不代表全部模型均已实测,也不保证每个长思考回合都能生成答案。

下一节列出的 v1.3.1 记录描述的是恢复功能引入前的行为。

验收情况

在 Windows 环境下针对真实上游实测。本节按轮次记录,并注明每项的验证方式——仅标注

「真实上游」与「实机点击」的条目才对应用户在界面上可见的行为。

Issue #12:验收状态

恢复实现、离线回归与真实上游结果单独记录在

docs/issue-12-recovery.md。合并前 review 修复了一处告警

重复累积的缺陷并补充回归用例,recovery 99/99、truncation

35/35、fingerprint 新增 11 项与 typecheck 均已通过;其中 12 项使用真实插件与本地 HTTP

验证转发成功、失败、客户端断开与统计落盘。最终全量结果以技术文档为准。

真实 MiMo Deep 首段在 304.161 秒自然 EOF,

恢复段 32.777 秒生成 4264 字符正文,以 stop / usage / [DONE] 正常结束;共两次

请求、336.942 秒。首段无 usage,汇总值仅为已知用量。首次 480 秒恢复失败记录

保留在技术文档中;真实 dsh UI 与其它模型尚未逐一验收。

历史:v1.3.2(对应 issue #11、#13、#19、#20、#21)

项目修复验证
#19 自更新信任链清单 Ed25519 签名(公钥 pin 在插件内,私钥不入仓)、feedUrl 与更新源彻底解耦、清单 base 只允许相对路径updater-test 新增签名/篡改/异钥/feedUrl 不跟随 4 组用例;release-e2e 负控改为在签名处拒绝
#19 转发口面localhost 绑定先执行 DNS 解析且要求结果全为回环;插件 API 请求体 1MB 上限(413);转发非 JSON body 返回 400、未知模型返回 404forward-test resolveLoopbackBind 三态用例;offline-test 404 用例
#20/#21 转发下工具不可调用(#21 报告的 Unknown tool 'bash'/'read'/'grep' 正是指纹诱饵四件套:车道强制声明这些名称,模型发起调用而转发客户端未注册)流式 tool_calls[].index 按调用重新编号,从 0 起(不再与 reasoning 共用块索引);指纹诱饵工具调用在转发口按块抑制(未命名块先扣留参数);参数被截断的回合流式同样返回 lengthforward-test 4 组流式/非流式用例(本地服务器 + 脚本化 lane)

| #20 dsh 内诱饵隐患 | s

内容取自仓库 README,未做删改性总结。命令与参数以原文为准。