zouyuxuan122/dsh-our-free-model

dsh-our-free-model

在 dsh 里装上这个插件即可,无需登录、注册或填 API Key,就能使用包括 Muse Spark 1.3、MiMo V2.6 在内的前沿模型——完全免费,不限量。 All you do is install this plugin in dsh: no login, no sign-up, no API key — the frontier models are just there, Muse Spark 1.3 and MiMo V2.6 among them. Completely free, with no usage cap.

Uncategorizedai-agentsdeepseekdeepseek-harness

dsh-our-free-model

简体中文 | English

你只需在 dsh 里装上这个插件,无需登录、注册、填 API Key 或任何其它操作,
就能用上包括 Muse Spark 1.3、MiMo V2.6 在内的前沿模型——完全免费,不限量。
*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 — Muse Spark 1.3, MiMo V2.6 and the rest.
Free, with no usage cap.*
模型清单跟随上游刷新,可用性由你自己这台机器的网络出口实测得出,
思考强度下发的是真实预算而不是提示词,另附一个 OpenAI 兼容的本地转发端口。
纯插件挂载:不改内核、无构建步骤、零依赖。

亮点

  • 装完即用,没有配置环节——不需要账号、不需要 Key、不需要去哪个后台开配额。
  • 上游写在明面上——只有一个来源:OpenCode 的 Zen 网关(https://opencode.ai),不经任何第三方中转。谁在服务你的请求、你的数据发到哪儿,见上游是哪些源。
  • 清单跟随上游——模型集合、上下文长度与能力每次刷新重新拉取,不是写死在插件里的一份快照。
  • 选择器只给真能用的模型——上游清单点名、但网关明确拒绝路由的模型(回 Model is unavailable、404 找不到这个 id)会从下拉框里移除,只在设置页留痕并写清拒因;网关自己的毛病(5xx)、配额(429)、超时断网这些不是对模型的判定,一律保持可达;地区门拦截的单独归到 region-limited 分组。整轮全部被拒时一律保留,绝不让选择器变空。
  • 公告中心 + 实时推送——仓库主人在仓库里编辑一份 JSON 并推送,所有安装最迟在一个轮询周期内收到;内容是白名单约束下的 HTML,支持图文排版;urgent 级别直接全屏弹窗;可选系统级通知。
  • 应用内升级——设置页一键升级:下载 → SHA-256 校验 → 备份 → 原子替换 → 校验回读 → 热重载,任一步失败自动回滚到上一个版本。
  • 热重载——升级与代码更新即时生效,不需要重启应用;也可在设置页手动触发,或开启文件监视自动重载。
  • 流式响应认出 body 而不是认出 header——网关在高负载下会用 application/json 的 content-type 回一整套 SSE 帧,插件按 body 的形状判定并把已嗅探的字节重新喂回流,既不会整轮报错,也不会因为一个 header 说谎就把能用的模型判成不可用。
  • 思考强度真的生效——Light / Balanced / Deep 对应输出 token 预算 2 048 / 8 192 / 模型上限,且逐次调用留痕。思考关不掉的模型(MiMo V2.6 这类)三档整体翻倍为 4 096 / 16 384 / 模型上限,因为思考与正文抢的是同一份额度;设置页每张模型卡都直接印出这一档实际会下发的上限。它不是把一个 effort 字符串丢给上游然后假装有用(原因见为什么用预算而不是 reasoning_effort)。
  • 无浏览器界面也能跑——插件只把 llm 当作硬依赖,没有 web server 的 composition(dsh-tui 这类)里照样启动、照样出模型;看板半身挂在一条自己的 fiber 上,等 webServer 出现再挂载,所以既不会把模型车道拖下水,也不会因为插件先于 web 服务加载就永远丢掉设置页。
  • 用量看板,全部留在本机——Token 热力图、总量曲线(可看总计或单个模型)、输出速度与首字延迟逐次采样。不上传任何东西。
  • OpenAI 兼容转发端口——本机其它工具用一个 base URL + Key 就能调用这些模型。
  • EAC 渠道(桌面端专属)——在 DeepSeek Harness 桌面端与 DSHEAC AIO 桌面端里自动解锁一条协付通道,模型以 EAC 前缀显示(如 EAC DeepSeek V4.1 Flash);凭据加密密封、宿主指纹闸门把守,命令行与其余宿主上整条通道不存在。见 EAC 渠道。
  • 接口有鉴权围栏——插件的 HTTP 路由优先级高于内核 /api,因此自带与内核一致的信任检查(优先复用 composition 的 connection 服务,缺失时退回结构化围栏)。

你会看到什么

输入框的模型选择器

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

被判定为「点名但不路由」的模型不出现在任何分组里——它们只在设置页的不在选择器中分组留痕, 带上拒因与探测时间,某一次探测重新通过后会自动回到选择器。

设置页 `设置 → Our Free Model`,六个分区:

  1. 模型清单——每个模型的可用性、视觉还是纯文本、上下文窗口、最长输出、各思考档位实际下发的

输出上限、实测首字延迟,以及一次单调用基准测试按钮。

  1. 公告中心——仓库主人推送的公告流:未读计数、紧急徽章、单条/全部已读、检查新公告按钮、系统通知开关。公告正文按白名单渲染 HTML。
  2. 用量看板——总览计数、17 周 Token 热力图、总量曲线(Token / 请求数切换,总计与单模型切换)、速度迷你图、按模型汇总表。
  3. 本地转发——开关、监听地址与端口、复制 base URL、显示 / 复制 / 轮换 API Key,并给出一条可直接跑的 curl 示例。
  4. 插件设置——总开关、是否展示地区受限模型、探测间隔、默认输出上限,以及当前探测到的出口 IP 与国家。
  5. 插件升级——当前/最新版本、检查更新、一键升级(含进度与失败原因)、最近一次升级历史、热重载按钮与文件监视开关。

首次启动公告——分 5 页(前言 / 模型清单 / 使用步骤 / 功能介绍 / 公告与升级),确认一次后不再弹,除非文案版本号被提升。

安装

命令行(纯 dsh web)

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

装完重启一次应用。--profile 填你实际使用的那个。

DSHEAC AIO / 桌面端:先看这段

桌面端在拉起 web 服务之前会跑一道 profile 闸门。它的扫描器只放行 dsh 自己在 .dsh-module-fallback 下生成的链接;profile 目录树里出现任何其它符号链接或目录 junction,应用会直接拒绝启动,报:

PROFILE_UPGRADE_REQUIRED: offline dependency migration is not yet available

所以桌面端不要用 `link:` 依赖安装,也不要建 junction。请用应用内的插件管理器, 或者放一个真实目录。

手工以真实目录安装,在 /profiles// 下做三件事:

  1. 把发布文件复制进 node_modules/dsh-our-free-model/

(index.js、client.js、adapter/、src/、locale/、icon.svg、cordis.patch.yml、package.json——adapter/ 不能漏:index.js 第一行就 import 它)

  1. dependencies 里加 "dsh-our-free-model": "1.4.4"——这个数字跟随仓库 `package.json` 的 `version`(改版本时同步,当前即 1.4.4),不要抄旧值,也不要写 `link:`
  2. dsh.profile.bundles 末尾追加 "dsh-our-free-model"
不要再往 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('<APP_ROOT>/sidecar/dist/lib/profile-upgrade.js');
const app = '<APP_ROOT>', profile = '<DSH_HOME>/profiles/<profile>';
console.log(g.planProfileUpgrade(app, profile));
g.assertProfileStartup(app, profile);
console.log('startup gate: PASS');
"

期望看到 status: 'compatible'、mismatches 为空数组,然后 PASS。 只想确认 bundle 组合是否正确、不启动界面:

DSH_HOME=<DSH_HOME> dsh --profile <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 警告会随重建一起消失。

使用说明

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

调思考强度:同一菜单里的 Effort,三档 Light / Balanced / Deep。档位越高,思考占用的 输出预算越多;上限是强制下发的,所以差异可测量,不是装饰。它是思考与可见回答共用的一 份额度,所以思考关不掉的模型会把三档整体抬高(设置 → Our Free Model 的模型卡上写着每一档 的实际数字)。如果觉得回答被截断,先换 Deep,或调高设置里的单次输出上限。

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

GET  /v1/models
POST /v1/chat/completions     流式与非流式
POST /v1/responses

端口被别的程序占着时,插件不会哑掉:先在同一端口重试几轮(刚关闭的监听、刚删掉的 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 常常已被占用或已被端口代理占着),应用后面板会显示实际端口与局域网地址。开启期间,能连到这台机器的任何人都可以用这把 Key 花掉本机的免费额度,所以只在信任的网络里开,必要时用防火墙限制来源网段。

重新核对地区:点"重新探测可用性",会按当前出口重跑探测。开/关 VPN 后再点一次, 地区受限模型会在两个分组之间自动迁移。

接收公告:一切自动。仓库主人推送新公告后,运行中的插件在一个轮询周期内(默认 30 分钟,也可在公告中心点"检查新公告"立即拉取)收到通知:普通公告弹 toast, urgent 级别直接全屏弹窗,两者都会出现在公告中心并保留未读标记。想同时收到 系统级通知,在公告中心点"开启系统通知"。

升级插件:设置 → Our Free Model → 插件升级 → 检查更新 → 立即升级。全过程 在应用内完成(下载 → 校验 → 备份 → 替换 → 热重载),不需要重新安装,也不需要 重启应用。升级失败会自动恢复上一个版本并给出原因。

实现结构

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 兼容监听器
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 文件里,不进入任何共享设置文档。

为什么用预算,而不是 reasoning_effort

实测过:在这条车道上把 reasoning-effort 字符串发给上游是空操作——三个不同名义档位 反复采样,思考 token 数量在统计上无法区分。做一个不起作用的控件比不做更糟, 所以思考强度实现为硬性输出 token 上限,它确实会约束——留痕的思考 token 随档位单调上升。

三个真实浪费过调试时间的内核行为

这里摘出来是因为任何写 provider 插件的人都会踩:

  1. `providerRetryPolicy()` 被原样存下来用。两版内核都不解析它,而退避调度器读的是

顶层的 initialDelayMs / maxDelayMs / jitterRatio。把这三项嵌在 backoff:{} 里, 它们读到 undefined,于是 undefined * 2ⁿ = NaN,而持久会话日志直接拒绝非有限数—— 一个本可恢复的瞬时故障就变成整轮对话报废。要返回已解析好的扁平策略。

  1. 一次被打断的工具调用会永久毒化该会话。没有对应结果的工具调用重放时上游回

400 invalid_request_error,此后该会话里每一次请求都失败。本插件在发送前修复配对, 三种线协议共用同一处修复。

  1. **没在 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 是唯一判据。

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