dsh-llm-proxy
Manifest validdsh plugin: per-host LLM outbound HTTP proxy routing (undici ProxyAgent) with a bundled dsh skill
dsh-llm-proxy
dsh 插件:SYSTEM proxy + LLM 分流代理。通过一个进程级 undici 路由 Dispatcher, 把 LLM 流量按配置列表分流到指定代理,其余流量走系统代理(启动环境变量),都没配则直连。
优先级语义
LLM 列表命中 > SYSTEM proxy(env 语义)> 直连
- 请求 origin 命中
llmProxy列表条目 → 走该条目指定的代理(undiciProxyAgent) - 未命中 → 走共享的 undici
EnvHttpProxyAgent,它自己处理HTTPS_PROXY/HTTP_PROXY/ALL_PROXY/NO_PROXY(大小写均兼容)——即标准 env 代理语义 - SYSTEM 也未配置 → 直连
环境变量只读不写:插件不会修改
process.env.HTTP_PROXY——对已启动进程无意义。
安装
# 方式一:作为 npm 插件加入 profile
dsh plugin add @aiwayds/dsh-llm-proxy
# 方式二:手动 patch 挂载(本包自带 cordis.patch.yml)
# 在 profile 的 bundles 中插入:
# - id: dsh-llm-proxy
# name: '@aiwayds/dsh-llm-proxy'
要求 dsh >= 0.1.7-rc.1 — 本插件只跟随 dsh RC/stable 线(CI 与发版在运行时解析 latest/next 中更新的 dist-tag)。不再支持 alpha 线。
⚠️ 最低宿主要求:0.2.0 起本插件声明
inject: ['skills'],要求宿主 dsh 提供 skills 服务(@deepseek-ai/dsh-skill0.1.1-rc 系列+)。无该服务的旧宿主上,本插件(含代理 路由功能)不会加载。
发布状态:本包已发布到 npm(0.2.0,自带内置 skill),方式一
dsh plugin add @aiwayds/dsh-llm-proxy即可直接用。
卸载
dsh plugin --profile <profile> remove @aiwayds/dsh-llm-proxy
宿主自动清理:profile 清单里的 dsh.profile.bundles 条目被摘除,本包的 patch 层随之卸下。
插件自身不在磁盘上留下任何状态——不写任何文件,环境变量只读不写;进程级 undici/fetch 全局接管的拆除是对称且经过测试的(test/dispose.test.mjs 覆盖 dispose 后 globals 还原与 HMR 窗口),dispose 干净。
会留存的只有手动安装的 skill(见上文 Skill 一节),需手工删除:
rm ~/.dsh/skills/dsh-llm-proxy-config # 手动拷贝/软链的副本
rm -r ~/.agents/skills/dsh-llm-proxy-config # npx skills add 装出的条目
Skill(内置使用指南)
本仓库自带一个 dsh skill(skills/dsh-llm-proxy-config/SKILL.md):面向 agent 的配置 + 排障
使用指南,frontmatter description 内嵌触发词(dsh 代理、HTTP 代理、LLM 分流、llmProxy、
407、CONNECT 挂起、SOCKS、NODE_USE_ENV_PROXY 等),进入每会话模型目录用于路由。三种获取方式:
-
随插件自动注册(零操作):通过 npm 包或 bundle(cordis.patch.yml)挂载本插件后, skill 随插件
apply()自动注册——进入每会话 skill 目录(<available_skills>, frontmatterdescription供模型路由),/dsh-llm-proxy手势可直接调出指南(已实测可用)。 -
GitHub 安装(不装插件,只要 skill):
npx skills add fan56/dsh-llm-proxy # 安装到 ~/.agents/skills/ -
手动:
git clone本仓库后,把skills/dsh-llm-proxy-config/拷贝或软链到~/.dsh/skills/:git clone https://github.com/fan56/dsh-llm-proxy.git ln -s "$(pwd)/dsh-llm-proxy/skills/dsh-llm-proxy-config" ~/.dsh/skills/dsh-llm-proxy-config
⚠️ 铁律:本包的 @deepseek-ai/* 只声明在 peerDependencies
(devDependencies 保留供本地构建)。请勿把它们挪进 dependencies——那会装出第二份
cordis 闭包,导致双实例崩溃(详见 dsh 生态 link-dsh-closure 机制)。
配置入口(插件 entry config / 设置页)
dsh 0.1.7 起,插件配置 = 插件声明的 static Config schema(声明即注册):本插件为
entry dsh-llm-proxy 声明了 enabled / systemMode / llmProxy 三个字段且全部
.volatile(),宿主据此在设置页生成表单,用户值落在 profile patch 里该 entry 的
config: 段;设置页改动免重启热生效(volatile-only 写入不重挂插件,本插件原地
重建 router,值未变的写入自动跳过重建)。
# profile 的 cordis.patch.yml(设置页写入也落在这里):
- id: dsh-llm-proxy
config:
enabled: true # 总开关,默认 true;false 时完全不动全局
systemMode: env # 'env'(默认,读环境变量)| 'off'(全部直连,仅 llmProxy 生效)
llmProxy: # 匹配列表,按顺序首条命中生效
- match: "api.deepseek.org" # 域名精确匹配(含任意端口)
proxy: "http://127.0.0.1:7890"
- match: "*.volces.com" # 通配:volces.com 本身 + 任意子域
proxy: "http://127.0.0.1:7891"
- match: "https://api.openai.com" # 完整 origin 精确匹配(大小写不敏感)
proxy: "http://127.0.0.1:7892"
要点:
- 旧
settings.yaml的dsh-llm-proxy:段自动迁移:0.1.7 宿主启动时把旧 settings.yaml 各段按「段名 = entry id」一次性导入 profile patch。本插件旧段名与 entry id 同为dsh-llm-proxy、三个键都在 volatile Config 里,存量用户值零手工迁移 (导入后旧文件被宿主改名为settings.yaml.imported)。 - entry id 必须是
dsh-llm-proxy(bundle patch insert 的 id)。旧 settings.yaml 段名 写成其他键(如llm-proxy:)不会被导入,静默失效。 - 编辑 热生效:volatile-only 改动不重挂插件,插件拆掉旧 router、按新配置原地重建, 无需重启。
- bundle entry config(
cordis.patch.ymlinsert 行的config:)作为 base 层仍然有效; profile patch/设置页值覆盖其上的同名键。 - 未挂载 settings 服务的宿主上,事件订阅自动休眠,entry config 照常生效。
match 规则
| 写法 | 含义 |
|---|---|
api.example.com | host 精确匹配,任意端口都算命中 |
api.example.com:8443 | host + 显式端口必须相等(https 默认 443 / http 默认 80 会补全比较) |
*.example.com | example.com 本身及任意层级子域 |
https://api.example.com | 完整 origin 精确匹配(scheme 也要一致) |
匹配全部大小写不敏感、纯词法比较(无 DNS/IO)。IDN 域名在匹配前统一归一化为 punycode
(中文.com 与 xn--fiq228c.com 两种写法等价,pattern 和 origin 两侧对称处理)。
实现为纯函数(src/match.ts),有完整单测。
proxy 协议限制
undici ProxyAgent 只支持 http:// 与 https:// 上游代理。
socks5:// 等 schema 在启动校验时直接报错(fail-fast),README 明说:SOCKS 不支持。
实现要点
- service start 时创建自定义 undici 路由 Dispatcher 并
setGlobalDispatcher(router); router 的dispatch()按 origin 分流:命中 → 该条的ProxyAgent(按 URL 缓存复用); 未命中 → 共享EnvHttpProxyAgent(或systemMode: off时直连Agent)。 - 照抄 pi-src 生产模板的防御细节:
undici.install?.()防 Node 内建 fetch 与 npm undici 版本偏斜 bug (Node 26 bundled fetch 经 npm undici dispatcher 不解压导致response.json()失败);用 pristine/owned 双守卫只在未被替换时 install。- undici Client 中途断流会发裸
error事件导致 unhandled crash——对本插件创建的 每个 dispatcher 挂 EventEmitter 级 error 兜底 listener(与 pi-srchttp-dispatcher.ts同款机制,覆盖进程内所有由本插件创建的 dispatcher)。
- HMR 重载窗口闭环:接管状态(原始 dispatcher/fetch + 活跃层列表)存放在
Symbol.for共享槽位,跨模块副本可见。cordisGroup.update先 create 后 remove、 vendor HMR 先 re-import 后 dispose——新版 apply 可能发生在旧版 dispose 之前; dispose 只摘除自己那一层,把 globals 还给最近的存活层,绝不打掉别人的路由器。 - dispose(cordis effect 语义)时非阻塞拆除:先把 globals 还回去(新请求立即不再
进入旧 router),再后台 fire-and-forget 地
close()排空在途请求——长 LLM 流式响应 不会拖住热重载。 - proxy URL 中可能出现的 userinfo 凭证(
user:pass@host)在日志/error message 里一律 脱敏为***@host。 - 与
NODE_USE_ENV_PROXY官方姿势的关系:本插件是等价替代——无需该变量、无需重启, 对新请求即时生效,且额外提供 LLM 分流能力。
手动 e2e 验证(CI 无网,不做真实请求测试)
# 1. 配一个本地回显代理(如 clash/mihomo 的 mixed-port 7890)
export HTTPS_PROXY=http://127.0.0.1:7890
# 2. 给 dsh-llm-proxy entry 配 llmProxy(设置页/profile patch),把某个 API 域名指到另一端口
# 3. 启动 dsh 后发起对话,观察代理访问日志:
# - llmProxy 命中域名的请求出现在该条代理日志里
# - 其他外网请求出现在 7890 日志里
# 4. unset HTTPS_PROXY 重启 → 只有 llmProxy 命中的流量走代理,其余直连
开发
npm run build # tsc -> lib/
npm run check # tsc --noEmit
npm test # node --test(match / router 探针分流 / config 边界 / skill 注册 /
# dispose 对称性 / e2e 全链路:apply → 全局 fetch 分流 → dispose 恢复 + HMR 窗口回归)
Comments
Loading…
Similar plugins
by Ye-Yu-Mo
DeepSeek Harness (dsh) 全局 HTTP 代理插件:undici setGlobalDispatcher + EnvHttpProxyAgent,配置化、热切换、可观测
★ 5
MIT
JavaScript
Aug 17, 2026
dsh plugin --profile web add dsh-llm-proxyby stayhpjinng
Provider-scoped HTTP/HTTPS forward proxy for DeepSeek Harness: configure independent proxy URLs and enable/disable switches per LLM provider, with environment-variable references for proxy credentials
★ 0
MIT
JavaScript
Aug 29, 2026
dsh plugin --profile web add dsh-provider-proxyby minatoAI
DeepSeek Harness fallback network proxy plugin: detects system proxies, probes overseas connectivity (Google/GitHub), routes dsh outbound HTTP through a working local proxy
★ 0
MIT
TypeScript
Aug 30, 2026
dsh plugin --profile web add dsh-net-proxy-pluginby lovstudio
Reusable LLM configuration profile library exposed to browser consumers as a Remote (DeepSeek Harness plugin)
★ 0
JavaScript
Sep 4, 2026
dsh plugin --profile web add @lovstudio/dsh-llm-configby looeton
DSH plugin: inject proxy environment variables at startup and self-check the whole proxy chain
★ 0
MIT
JavaScript
Sep 10, 2026
dsh plugin --profile web add dsh-plugin-proxy-envby LeslieWylie
Per-conversation LLM billing display for the DSH web composer, for anyone self-hosting a New API / One API-compatible gateway.
★ 0
MIT
JavaScript
Aug 17, 2026
dsh plugin --profile web add dsh-gateway-billing