English | 简体中文
dsh-net-proxy-plugin
DeepSeek Harness 的本地网络代理兜底插件(bundle):自动扫描系统里已有的网络代理(环境变量、Windows 系统代理、macOS/Linux 系统代理、常见本地代理端口),探测海外网站(默认 Google 204 与 GitHub)的连通性;当直连不通而某个本地代理可用时,把该代理接入正在运行的 dsh —— 进程内所有 fetch 走该代理,并同步设置 HTTPS_PROXY/HTTP_PROXY/NO_PROXY 环境变量,让 agent 启动的 git、pnpm 等子进程同样可用代理。
这是兜底方案,不是默认接管:没有可用代理或直连正常时,dsh 的行为与未安装本插件完全一致;卸载时精确恢复环境变量与全局 dispatcher。
更新日志
此处仅展示最新版本,完整版本历史见 change-log.md。
0.1.0(2026-08-31)
- 首发 即插即用,无需构建安装(仓库已提交构建产物
lib/)。
功能
- 自动发现候选代理(优先级去重):
extraProxies配置 → 环境变量(HTTPS_PROXY/HTTP_PROXY/ALL_PROXY及小写)→ 系统代理(Windows WinINet 注册表、macOSscutil --proxy、Linux GNOME gsettings)→ 本地监听端口(默认 7890/7897/7891/10809/10808/8888/8080,http 与 socks5 两种都试)。 - 连通性探测:直连 + 逐候选,对每个目标发一次 GET;返回 HTTP 状态码 < 500 视为可达。
- 自动决策(
activation: auto默认):有代理能全量到达目标且直连存在失败目标 → 激活该代理;activation: always则只要有可用代理就激活。默认每 5 分钟复检一次(reprobeIntervalMs: 0关闭),VPN 断开自动切回直连、重开后再次激活;/net-proxy refresh可立即重检。 - 激活范围:进程内所有 fetch(undici 全局 dispatcher 换成按主机名路由的
RoutingDispatcher,bypassHosts内的主机仍直连;覆盖 LLM、web_search 等)+ 子进程(标准代理环境变量 +NO_PROXY)。 - 可选的
net-proxy提供方:web_fetch内置web-fetch-http提供方为安全起见自建连接、不走全局 fetch 代理;本插件提供语义一致的兼容提供方,可一键切换(见下)。 /net-proxy命令:Web UI 里查看插件当前状态,/net-proxy refresh立即重检。
实测记录
开发期间在真实环境(Windows + VPN 系统代理 http://127.0.0.1:51266)验证:插件启动后检测到直连 GitHub 失败、系统代理全量可达 → 自动激活;随后模型首次 web_fetch 直连失败、重试经代理返回 204 —— 正是「超时后重试走本地代理」的路径。dsh 日志输出 dsh-net-proxy: probe done — direct blocked, working proxies: ..., active: http://127.0.0.1:51266。
单机单次记录,结果受当天网络影响;不同机器/代理环境下以插件自身的探测输出为准。
安装
仓库地址:https://github.com/minatoAI/dsh-net-proxy-plugin
插件按 bundle 方式分发,用 dsh plugin 安装进 profile(从源码 checkout 运行时用 pnpm dsh 代替 dsh):
从 GitHub 安装。仓库已提交构建产物
lib/,无 build 脚本,无需 allowBuilds 授权
dsh plugin --profile web add github:minatoAI/dsh-net-proxy-plugin
更稳妥:固定到某个 commit,避免后续推送改变实际安装到的代码
dsh plugin --profile web add github:minatoAI/dsh-net-proxy-plugin#<commit-sha>
或本地文件夹安装(开发调试用,需先构建)
pnpm install
pnpm run build
dsh plugin --profile web add ./dsh-net-proxy-plugin
安装完成后重启 dsh(新 bundle 在下次启动时生效):
dsh --profile web
安装时仅从 npm 拉取唯一运行时依赖 undici;@deepseek-ai/cordis、@deepseek-ai/schemastery、@deepseek-ai/dsh-web 是 peerDependencies,运行时从 dsh 安装目录解析,不需要额外安装。
使用
启动后代理检测自动进行。首次探测需要几秒钟(直连 + 各候选 × 目标,每个最多 probeTimeoutMs);此窗口内发起的一次直连请求可能失败,下一次重试就会命中已激活的代理。
- 激活成功:dsh 日志输出
dsh-net-proxy: activated <url> (system, ...)与probe done摘要。 - Web UI 输入
/net-proxy查看当前状态(激活的代理、来源、激活时间、直连可达性),/net-proxy refresh立即重检。
配置
在 profile 的 cordis.patch.yml 里覆盖 net-proxy 行:
- id: net-proxy
config:
targets: [https://www.google.com/generate_204, https://github.com]
probeTimeoutMs: 5000
reprobeIntervalMs: 300000
bypassHosts: [localhost, 127.0.0.1, ::1, api.deepseek.com, "*.deepseek.com"]
extraProxies: [http://127.0.0.1:7890]
probePorts: [7890, 7897, 10809]
activation: auto
| 字段 | 默认 | 说明 |
|---|---|---|
enabled |
true |
总开关 |
targets |
https://www.google.com/generate_204, https://github.com |
连通性探测目标 |
probeTimeoutMs |
5000 |
单次探测超时 |
reprobeIntervalMs |
300000 |
周期复检间隔;0 关闭 |
bypassHosts |
localhost, 127.0.0.1, ::1, api.deepseek.com, *.deepseek.com |
激活后仍直连的主机(精确 / *.domain 通配 / *) |
extraProxies |
[] |
手动指定的代理,优先于自动发现 |
probePorts |
7890, 7897, 7891, 10809, 10808, 8888, 8080 |
扫描的本地端口 |
activation |
auto |
auto:直连失败才启用;always:有可用代理即启用 |
fetchTimeoutMs |
30000 |
net-proxy web 提供方超时 |
maxResponseBytes |
5000000 |
net-proxy web 提供方响应上限 |
maxRedirects |
5 |
net-proxy web 提供方同源重定向上限 |
让 web_fetch 工具也走代理
web_fetch(dsh 内置 web-fetch-http 提供方)为安全起见自建连接、固定公网 IP,不经过全局 fetch 代理。本插件提供语义一致的 net-proxy 提供方(WEB_FETCH_TIMEOUT/WEB_ABORTED/WEB_REDIRECT_BLOCKED/WEB_BLOCKED_URL/WEB_FETCH_TOO_LARGE 等错误码与内置一致;走代理时公网 IP 校验由你选用的代理承载)。在你的 profile 的 cordis.patch.yml 里改一行即可启用:
- id: web
config:
searchProvider: deepseek-official
fetchProvider: net-proxy
不配置时 web_fetch 维持原有的直连安全路径,不受本插件影响。
网络与代理(中国大陆用户)
插件读取的是系统里已有的代理,不内置任何代理服务。VPN/代理开启时自动发现并复用;VPN 重启换了端口也会在下一次复检(默认 5 分钟)或 /net-proxy refresh 后自愈。请只使用你信任的本地代理 —— 代理会看到并转发你通过它的全部流量;插件不会修改 Windows 系统代理设置,仅影响 dsh 进程及其子进程的网络访问。
卸载
dsh plugin --profile web remove dsh-net-proxy-plugin
仓库结构
dsh-net-proxy-plugin/
├── package.json # manifest: "dsh": { "bundle": {"patch": ...} };构建产物 lib/ 随仓库提交
├── cordis.patch.yml # 组合层:单个行 net-proxy(name: dsh-net-proxy-plugin)
├── src/ # TypeScript 源码(NodeNext ESM,strict)
│ ├── index.ts # 插件主体:配置 Schema、探测调度、激活决策、提供方/命令注册、生命周期
│ ├── candidates.ts # 候选发现(配置→环境变量→系统代理→本地端口);系统代理读取(WinINet/scutil/gsettings)
│ ├── probe.ts # 直连/逐代理连通性探测
│ ├── dispatcher.ts # undici 代理 dispatcher 与按主机名路由的 RoutingDispatcher
│ ├── activate.ts # ProxyActivation:全局 dispatcher 与代理环境变量的激活/停用/切换恢复
│ ├── bypass.ts # 主机匹配(精确 / *.domain 通配)与 NO_PROXY 值生成
│ └── fetch-provider.ts # 可选的 net-proxy WebFetchProvider(同源重定向/大小上限/超时/错误码)
├── lib/ # 构建产物(已提交,GitHub 安装开箱即用)
├── tests/ # vitest:40 个用例(解析/路由/探测/激活/提供方/系统代理集成)
├── README.md # 简体中文说明(本文件)
├── README.en.md # English README
├── change-log.md # 完整版本历史(简体中文)
└── change-log.en.md # 完整版本历史(English)
开发说明
- 组合层遵循 dsh 约定:单个行
net-proxy,name为精确包名dsh-net-proxy-plugin(client-modules 扫描按行名定位根 manifest)。 - 插件
inject为空:探测调度与激活不依赖任何服务,启动即工作;web/commands为可选服务,通过ctx.inject注册提供方与命令 —— 组合里没有对应服务时相关功能自动不注册,不会造成 loader 启动挂起。 - 所有注册都是 effect(
ctx.effect/yield返回 disposer),生命周期 effect 负责清理复检定时器并activation.dispose()(恢复全局 dispatcher 与代理环境变量)。 src/相对导入带.js后缀(tsc NodeNext 输出要求);tsconfig.json开启strict、noUncheckedIndexedAccess、exactOptionalPropertyTypes。
测试
pnpm install
pnpm test # vitest:40 个用例
pnpm run build # tsc 输出 lib/
dsh plugin check . # 用 dsh 校验 patch 层与插件挂载(从 fork 源码运行时用 pnpm dsh)
测试使用本地 mock 代理(HTTP 绝对形式 + CONNECT 隧道)与真实目标服务器路由,覆盖候选解析、主机匹配/NO_PROXY、RoutingDispatcher、探测/决策、激活/停用/切换恢复、WebFetchProvider 契约等 40 个用例。
注:
dsh plugin check会提示unknown inject dependencies: commands—— 这是检查工具自身已知服务清单未收录commands的提示(组合中实际存在),不影响安装与运行。
No comments yet. Be the first to write one.