Skip to content
dsh.fish
Bundle

dsh-llm-proxy

Persistent global fetch proxy for DeepSeek Harness LLM requests (undici setGlobalDispatcher + EnvHttpProxyAgent), configured via the llm-proxy settings namespace

Source
Ye-Yu-Mo
stars
5 stars
License
MIT
Updated
Updated 7 days ago

Readme

# dsh-llm-proxy

> DeepSeek Harness (dsh) 的全局 HTTP 代理插件:用 undici `setGlobalDispatcher` + `EnvHttpProxyAgent` 接管 dsh 所有 LLM 请求的代理路由。配置化、热切换、可观测。

[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Node](https://img.shields.io/badge/Node-%3E%3D24-brightgreen)](package.json)
[![dsh](https://img.shields.io/badge/DeepSeek%20Harness-0.1.x-6b3fa0)](package.json)

---

## 为什么需要它

dsh(DeepSeek Harness)用 node 内置 `fetch`(undici)发 LLM 请求,而 undici **默认不读 `http_proxy`/`https_proxy` 环境变量**。如果你的 LLM 端点(如 llm-proxy 网关)必须走代理才能访问,dsh 会直连超时。

本插件在 dsh 进程内用 `setGlobalDispatcher(new EnvHttpProxyAgent(...))` 全局接管 fetch 的代理路由:

- ✅ 让 dsh 所有 LLM 请求走你配置的代理
- ✅ **热切换**:设置变更即时生效,无需重启
- ✅ **可逆**:插件停止/禁用时恢复基线 dispatcher,不留进程级残留
- ✅ **可观测**:`/api/llm-proxy/status` 查看当前生效模式,`/api/llm-proxy/test` 测试任意代理连通性

## 安装

本插件是 **bundle** 包(`dsh.bundle.patch` 清单):`dsh plugin add` 会把它装进 profile 依赖并自动加入 `dsh.profile.bundles`,下次启动自动激活,**无需手动加 patch 行**。

```bash
# 一键安装(发布到 npm 后可直接用包名)
dsh plugin --profile web add dsh-llm-proxy
# 或直接从 GitHub 安装
dsh plugin --profile web add github:Ye-Yu-Mo/dsh-llm-proxy
```

开发调试(本地 link):

```bash
git clone https://github.com/Ye-Yu-Mo/dsh-llm-proxy
dsh plugin --profile web add link:$(pwd)/dsh-llm-proxy
```

安装后**重启 dsh web** 使 bundle 补丁生效;`~/.dsh/dsh.log` 出现 `[llm-proxy]` 日志(未启用时为「恢复基线」一行)即装载成功。

## 配置

通过 dsh 设置页的「LLM 代理」项,或直接编辑 `~/.dsh/settings.yaml`:

```yaml
llm-proxy:
  enabled: true
  url: http://127.0.0.1:7891        # 你的 HTTP(S) 代理地址
  noProxy:
    - localhost
    - 127.0.0.1
    - ::1
```

| 字段 | 类型 | 默认 | 说明 |
|------|------|------|------|
| `enabled` | boolean | `false` | 是否启用代理接管 |
| `url` | string | `''` | HTTP(S) 代理地址,如 `http://127.0.0.1:7891` |
| `noProxy` | string[] | `['localhost','127.0.0.1','::1']` | 不走代理的地址 |

> ⚠️ dsh 设置页只暴露白名单内的配置命名空间。若设置页显示「表单不可用」,需把 `llm-proxy` 加入 `dsh-host-apiproxy` 的 `WEB_SETTINGS_NAMESPACES`(当前为 dsh 已知限制,见下)。

## HTTP API

插件注册两个宿主路由(loopback-only,防 LAN 探测):

### `GET /api/llm-proxy/status`

当前生效模式:

```json
{
  "effective": { "mode": "setting", "url": "http://127.0.0.1:7891" },
  "env": { "httpProxy": "http://127.0.0.1:7891", "httpsProxy": "http://127.0.0.1:7891" }
}
```

`mode` 取值:
- `setting`:走设置的 `url`
- `env`:读环境变量代理(`HTTP(S)_PROXY`)
- `direct`:直连(无代理)

### `POST /api/llm-proxy/test`

测试任意代理到目标端点的连通性:

```json
// 请求
{ "url": "http://127.0.0.1:7891", "probeUrl": "https://llm-proxy.ftai.chat/v1/models", "timeoutMs": 8000 }
// 响应
{ "ok": true, "latencyMs": 246, "status": 200 }
```

## 开发

```bash
pnpm install
pnpm test        # 单元测试(logic/http-utils)
node scripts/... # 见 scripts/
```

目录结构:

```
lib/
  index.js       # 宿主核心:settings + dispatcher 接管 + HTTP 路由
  logic.js       # 纯函数配置判定(可单测)
  http-utils.js  # loopback 校验 / JSON 读写
  client.js      # 设置面板「LLM 代理」页
test/            # 单元测试
```

## 已知限制

dsh 设置页的配置命名空间白名单(`dsh-host-apiproxy` 的 `WEB_SETTINGS_NAMESPACES`)是硬编码的,第三方插件无法自注册暴露。目前需要手动把 `llm-proxy` 加入白名单才能让设置页表单可用(dsh 官方已将"插件自注册"列为延后工作)。

已在上游提交讨论:[Third-party plugins cannot expose settings namespaces to the web settings page](https://github.com/deepseek-ai/deepseek-harness/discussions/1196)(Ideas 分类)。

## License

MIT

Install

dsh plugin --profile web add github:Ye-Yu-Mo/dsh-llm-proxy#2679d6ccd2375b4c9ac85d8a8a806a18cf906779

Profile: web

Source