让任何会说 HTTP 的东西驱动 DSH:47 条路由(REST + SSE),覆盖工作区、会话(创建/提示、SSE 实时生成、历史、统计、任务清单、中止、问答)、模型与全局默认模型、提供方、Agent Preset、设置命名空间、技能与工作区文件(含分片续传上传),另有 OpenAI 兼容的 /chat/completions、内置 OpenAPI 3.0 规范与在线调试页。它只 inject 宿主的 webServer 与 tools,挂在宿主 webserver(默认前缀 /api/v1)或独立端口,可选 API Key 鉴权,并自带一份教会 DSH 里 Agent 调用本 API 的 SKILL。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-web-service
# Release 预构建包
dsh plugin --profile web add "https://github.com/toddpan/dsh-webapi/releases/latest/download/dsh-web-service.tgz"
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:toddpan/dsh-webapi
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
English | 中文
第一次用?先看图文版 使用教程。
把 DeepSeek Harness 通过 HTTP 开放出来:DSH 里的工作区、会话、模型、设置、技能与文件直接变成
REST 接口与 SSE 流,再加一个 OpenAI 兼容的 /chat/completions,现成的 OpenAI 客户端不用改就能接到 DSH。
典型用法:给 DSH 做一个自托管控制台、桌面或移动端客户端、驱动 Agent 的 CI/自动化流程、 把 DSH 当成工具调用的其它 Agent,或在 DSH 前面再包一层自己的 API 网关。
- 零新增依赖:插件只
injectwebServer与tools,路由挂在 DSH 宿主的 webserver 上,并可另开一个可随时启停的独立固定端口服务。 - 80+ 条路由(REST + SSE),内置 OpenAPI 3.0 规范、在线调试页,以及可启停独立 API 服务的设置页。
- 自带 SKILL:
skills/dsh-web-service/SKILL.md教会 DSH 里的 Agent 调用本 API(流式、中止、 回答挂起问题、上传文件等)。
安装
兼容 DSH 0.1.0–0.2.x(peer 范围见 package.json;已在 0.1.7-rc.2 上运行验证,并在 0.2.0-rc.2 上通过类型检查与运行时装配验证)。
方式一:预构建 tarball(推荐,免构建、免 allowBuilds 授权)
dsh plugin --profile web add \
https://github.com/toddpan/dsh-webapi/releases/latest/download/dsh-web-service.tgz
dsh plugin 会把该包写进 profile 的 package.json(依赖 + dsh.profile.bundles);
带 HMR 的 profile 会立即装配,否则重启 DSH 生效。探活:
curl -s http://127.0.0.1:3080/api/v1/system/status # {"ok":true,...}
curl -sI http://127.0.0.1:3080/api/v1/docs # HTTP/1.1 200 OK
升级提示。 资产名不带版本号,
latest/download/dsh-web-service.tgz对全新安装永远指向最新构建; 但包管理器可能复用该 URL 的旧解析结果。要把已有安装切到确定版本,用带版本号的资产:dsh plugin --profile web add https://github.com/toddpan/dsh-webapi/releases/download/v0.1.11/dsh-web-service-0.1.11.tgz
方式二:直接从 git 仓库安装(插件管理器的「GitHub 仓库地址」安装方式)
dsh plugin --profile web add github:toddpan/dsh-webapi
lib/ 已入库,所以从 git 装的包可直接运行。lib/ 与 src/ 保持同步——改动 src/ 后,
请在同一次改动里重新构建并提交 lib/。
方式三:从源码构建(需要一份 DSH 源码 checkout)
git clone https://github.com/toddpan/dsh-webapi && cd dsh-webapi
DSH_CHECKOUT=/path/to/deepseek-harness bash scripts/build.sh # src/ → lib/
dsh plugin --profile web add "$PWD"
scripts/build.sh 会从 checkout 软链 cordis / schemastery / @deepseek-ai/* 等 peer,无需 npm install。
配置
全部可选,装好后写在 profile patch 的插件行 config 里(默认值见 src/index.ts):
| 字段 | 默认 | 说明 |
|---|---|---|
pathPrefix |
/api/v1 |
路由前缀 |
apiKey |
'' |
非空则开启鉴权,请求需带该 key |
standalonePort |
0 |
首次安装时的初始端口;0 = 自动分配(31800-31899)。分配后以设置页为准,配置不再覆盖 |
standaloneBindIp |
127.0.0.1 |
首次安装时的初始监听范围:127.0.0.1(仅本机)或 0.0.0.0(局域网可达);之后以设置页为准 |
cors |
true |
是否允许跨域 |
defaultCwd |
'' |
默认工作目录,留空取 process.cwd() |
maxUploadBytes |
2 GiB |
上传大小上限,大文件建议走分片接口 |
adminRemoteAccess |
false |
是否允许非回环地址访问 API Key 管理接口;默认仅本机可管理密钥 |
apiKey只是「遗留单 Key」,向后兼容用。日常管理请到设置页生成/吊销多条 Key,详见 API Key 管理。
API 服务(独立固定端口)
插件自带一个独立的 HTTP 服务,与 DSH 主 webserver 解耦——主端口每次启动都会变, 独立服务端口固定,适合写进三方客户端、脚本或反向代理。
- 首次安装自动分配端口:从 31800 起找空闲端口,分配后固定不变。
- 在设置页启停:
GET /api/v1/settings/api-keys→ 「API 服务」卡片;端口与监听范围 (127.0.0.1仅本机 /0.0.0.0局域网)随时可改,即时生效、无需重启 DSH。 - API 地址实时显示:改端口或监听范围时,地址区随表单实时预览;运行中显示真实地址,可一键复制。
- 状态持久化:运行中的服务在 DSH 重启后自动恢复同一端口;停止后重启 DSH 仍保持停止。
设置文件:<DSH_HOME>/dsh-web-service/service-settings.json(0600)。旧版 fixedPort
格式会在读取时自动迁移。
| 操作 | 接口(管理令牌鉴权) |
|---|---|
| 读取状态 | GET /api/v1/api-keys/service |
| 启动 / 换端口 / 换监听范围 | POST /api/v1/api-keys/service/start { "port": 31800, "bindIp": "127.0.0.1" } |
| 停止 | POST /api/v1/api-keys/service/stop |
| 建议空闲端口 | GET /api/v1/api-keys/service/free-port |
| 旧版兼容 | GET / PUT /api/v1/api-keys/port(fixedPort: 0 表示停止) |
启动绑定失败(端口被占用等)返回 409,原监听回滚,现状不变。
API Key 管理(设置页)
打开 GET /api/v1/settings/api-keys 即可在一个页面里管理独立 API 服务与三方调用鉴权的密钥:
查看(脱敏)、新建、轮换、吊销、开启/关闭鉴权。/docs 页头部也有「管理 API Key」入口。
三个入口
| 入口 | 说明 |
|---|---|
| DSH Web GUI 侧边栏「API 服务」 | 插件自带浏览器半边(client half),装好并重启 DSH 后出现在侧边栏,内嵌本页 |
GET /api/v1/settings/api-keys |
独立页面,可直接收藏 |
/docs 页头「管理 API Key」按钮 |
从 API 文档一键跳转 |
页面按管理令牌闸门设计:密钥管理与普通 API 调用是两套凭证。首次打开会要求输入管理令牌,
页面会直接给出取令牌的命令(在运行 DSH 的机器上执行):
cat <DSH 配置根>/dsh-web-service/admin-token,粘贴一次后保存在浏览器 localStorage。
未通过闸门时,页头的「新建 API Key」等管理按钮一律收起——不会出现「点了按钮才报 401」的死胡同。
页面主题与离线可用
/docs、/docs/reference、/settings/api-keys 三个页面统一使用 HARNESS 设计令牌
(--dsw-alias-*,取值镜像 packages/client/ui-theme/src/styles/design-platform.css),
因此配色、圆角、字号与 DSH Web GUI 一致,并同时支持浅色 / 深色:
- 内嵌在 GUI 侧边栏时(同源 iframe)直接读取父页面的令牌计算值并实时跟随其明暗切换, 用户自定义主题同样生效;
- 独立打开时按系统
prefers-color-scheme,也可用?theme=light/?theme=dark强制。
Swagger UI 资产随包自托管在 vendor/swagger-ui/,由 /api/v1/docs/assets/* 提供,
不依赖任何公共 CDN,内网或离线环境同样可以打开 /docs/reference。
内嵌在 GUI 侧边栏时,页内的「SWAGGER / 查看 OpenAPI JSON / 交互式文档」等按钮会在面板内跳转
(目标页给出「← 返回」按钮)。原因:DSH Desktop 主窗口显式拒绝一切新窗口
(webContents.setWindowOpenHandler(() => ({ action: 'deny' }))),target="_blank" 在应用内是
静默失败;外部链接(GitHub / 问题反馈)仍会尝试新窗口,被拒时提示复制链接。
新建时有两种 Key 值来源,对应 POST /api-keys 的 plaintext 字段:
| 方式 | 行为 |
|---|---|
| 随机生成(默认) | 服务端生成 dsk_ + 32 字节 CSPRNG(256 位熵) |
| 使用自定义 Key | 粘贴你已有的 Key(16-256 位可见 ASCII),用于接入既有客户端或迁移 |
自定义 Key 的强度由你负责,因此它连前缀都不展示(列表里标记「自定义」)——否则一个
my-secret-api-key-xxx露出前 12 位就泄露了大半价值。服务端同样只保存哈希。 同值的有效记录会被拒绝(400);已吊销 / 已过期的值可以重新登记。
两套凭证,互不通用
| 用途 | 凭证 | 头部写法 |
|---|---|---|
| 调用业务接口(数据面) | API Key | Authorization: Bearer <key> 或 X-API-Key: <key> |
| 管理密钥(管理面) | Admin Token | Authorization: Bearer <admin-token> 或 X-Admin-Token: <admin-token> |
这样持有 API Key 的三方客户端无法给自己增发密钥。Admin Token 由插件首次启动时自动生成,
存放在 DSH 配置根下的 dsh-web-service/admin-token(权限 0600):
cat "${DSH_HOME:-$HOME/.dsh}/dsh-web-service/admin-token"
安全约定
- 落盘只存两项:
sha256(明文)(鉴权用)和一份可逆密文sealed(列表页「复制」用)。sealed是用管理令牌经 HKDF 派生的密钥做的 AES-256-GCM;因此api-keys.json单独泄露 (备份、截图、贴到 issue)还原不出 Key,还需要同目录下 0600 的admin-token。 - 列表页每条 Key 都有「复制」按钮,明文通过管理令牌鉴权的接口现取现用,只写进剪贴板, 不进 DOM、不写 localStorage、不打日志。
- 加密存储上线之前创建的 Key 只有哈希,明文不可恢复 —— 点「复制」会直接引导到「轮换」生成新 Key; 管理令牌被删除重建后,旧密文的解密封装也随之失效,同样表现为「不可复制,请轮换」(不会静默给错值)。
- 管理接口默认只允许本机(回环)访问;远程管理需显式设置
adminRemoteAccess: true。 浏览器请求一律做同源校验(防 CSRF / DNS rebinding),跨源返回403 FORBIDDEN_ORIGIN。 - 吊销立即生效且不可恢复;轮换会让旧 Key 立即失效——更稳妥的做法是先「新建」替代 Key 分发, 确认切换完成后再吊销旧的。
- 插件配置里存在
apiKey时鉴权被强制开启,页面上无法关闭(防止误放松保护); 没有任何有效 Key 时也不允许开启鉴权,避免把自己锁在外面。 - 密钥存储文件损坏时按 fail-closed 处理:不放松鉴权,
/system/status会报keysStoreDegraded。 损坏文件会改名为api-keys.json.corrupt-<时间戳>保留取证,并自动从api-keys.json.bak(每次成功写入后更新的「最后已知良好状态」)恢复,不会静默丢弃既有密钥记录。 - 管理接口的回环判定看的是 TCP 对端地址。若 DSH 前面挂了反向代理 / 隧道(例如把端口转发到公网),
插件会把代理端当成对端地址,此时回环护栏形同虚设——必须自行在网络层收口,或保持
adminRemoteAccess: false并只在本机做管理操作。 - 数据面(业务接口)的鉴权是 Bearer / API Key 校验,不含同源校验:它本来就面向跨域三方客户端,
因此浏览器页面携带有效 Key 的跨源请求属于预期能力;跨域放行范围由
cors控制。 - 管理令牌会保存在浏览器
localStorage,公用电脑用完请在页面上「清除本机管理令牌」。
数据文件位于 <DSH_HOME>/dsh-web-service/api-keys.json(0600)。
功能特性
- 工作区管理 (Workspaces):添加、删除、修改、查询工作区及其关联会话。
- 会话管理 (Sessions):添加、删除/归档、修改标题/模型、列表查询及消息历史记录分页。
- 设置与模型管理 (Models & Settings):查询可用模型列表、提供方列表、获取与修改系统全局默认模型配置。
- 会话流式交互 (Streaming):
POST /sessions/:id/prompt-stream:基于 Server-Sent Events (SSE) 实时推送delta、reasoning、tool_call、tool_result与turn_end。GET /sessions/:id/events:会话底层事件总线实时广播监听通道。- 流式与超时语义(重要):三个对话入口(
prompt/prompt-stream/chat/completions)均采用停滞看门狗而非「整轮总时长」上限 —— 持续产出(长文本生成、多轮工具调用)哪怕远超数分钟也绝不截断,只有持续收不到任何会话事件(真停滞)才显式报错收流;同timeoutMs(同步入口停滞阈值,默认 180s)、stallTimeoutMs(流式入口停滞收流阈值,默认 300s)。所有 SSE 通道每 15s 下发一遍': ping'注释帧心跳,防中间代理/网关在长沉默期掐流;流内任意内部错误都会以error事件显式可见(不再无声消失)。
- OpenAI 兼容协议:
POST /chat/completions:支持标准 OpenAI 客户端调用(兼容stream: true/false)。
- 交互式 Web UI 文档 & OpenAPI 规范:
- 内置交互式 API 测试面板:
GET /api/v1/docs - OpenAPI 3.0 规范:
GET /api/v1/openapi.json
- 内置交互式 API 测试面板:
- 交互式会话:读取挂起的
ask_user_question问题并经 REST 作答、中止正在跑的轮次、 上传/列出/下载工作区文件(含分片续传上传)。 - API 服务与密钥设置页:
GET /api/v1/settings/api-keys一页管理独立服务的启停/端口/监听范围 (地址实时预览)与三方调用密钥——多 Key 并存可命名、脱敏展示、新建/轮换/吊销、列表一键复制、 开启关闭鉴权;落盘存哈希 + 管理令牌加密的密文。
API 路由汇总
默认基础前缀:/api/v1
| 模块 | 方法 | 路径 | 说明 |
|---|---|---|---|
| System | GET |
/system/status |
系统状态、在线模型及端口信息 |
GET |
/ping |
机器指纹(IP/MAC),判定 127.0.0.1(natpass 隧道)节点是否本机 | |
| Workspaces | GET |
/workspaces |
查询工作区列表 |
POST |
/workspaces |
创建/添加工作区 | |
GET |
/workspaces/:id |
获取工作区详情 | |
PUT |
/workspaces/:id |
修改工作区标题 | |
DELETE |
/workspaces/:id |
删除工作区绑定 | |
GET |
/workspaces/:id/sessions |
查询工作区下的会话 | |
| Sessions | GET |
/sessions |
查询会话列表 (支持搜索和工作区过滤) |
POST |
/sessions |
创建新会话 | |
GET |
/sessions/:id |
查询单个会话详情与状态 | |
PUT |
/sessions/:id |
修改会话 (标题/模型) | |
DELETE |
/sessions/:id |
删除/归档会话 | |
GET |
/sessions/:id/history |
分页查询会话历史消息 | |
GET |
/sessions/:id/stats |
会话实时统计:轮/步、LLM 与工具调用耗时、首 token 均值、解码吞吐、缓存命中、token 账本(对齐 harness session-stats 投影语义) | |
GET |
/sessions/:id/todos |
会话任务清单 + 运行时长:todos[{content,status}](todo_write 整表投影,turn/start 清空)、counts{completed,inProgress,pending}、running/elapsedMs(当前或最后一轮 turn 墙钟)、turnStartedAt/turnEndedAt/updatedAt(供三方控制台渲染「任务」面板,≥0.1.8) |
|
GET |
/sessions/:id/skills |
会话作用域技能目录(按会话 cwd 解析技能根,支持 ?search= 过滤;供输入框 "/" 技能候选,对齐 harness skills/list) |
|
GET |
/sessions/:id/questions |
查询会话当前挂起的 ask_user_question 问题批次(REST 集成的宿主侧答复桥,≥0.1.7;含 connection 层抢答绕过;≥0.3.7 起仅按 ALS 归属 REST 会话,GUI/浏览器来源的提问一律透传,修复 GUI 提问 UI 不显示的回归) | |
POST |
/sessions/:id/answers |
提交挂起问题的答复(answers: [{id, selected, custom?}]),resolve 后工具以普通 tool/result 返回、会话继续 |
|
POST |
/sessions/:id/cancel |
中止会话轮次 | |
POST |
/sessions/:id/files |
上传文件到会话工作区 (multipart 多文件 或 raw+?filename=);同名自动 -1/-1 去重,AI 可用文件工具直接读取 | |
GET |
/sessions/:id/files |
列出会话工作区目录(?path= 浏览相对子目录,目录优先排序) | |
GET |
/sessions/:id/files/download |
下载工作区文件(?path= 相对路径;?inline=1 浏览器内联预览) | |
| Streaming | POST |
/sessions/:id/prompt-stream |
SSE 流式发送提示词并接收生成 |
GET |
/sessions/:id/events |
SSE 会话全局事件监听订阅 | |
POST |
/sessions/:id/prompt |
同步等待对话结果 | |
| OpenAI | POST |
/chat/completions |
兼容 OpenAI Chat 协议 (流式/非流式) |
| Models | GET |
/models |
查询可用模型清单与默认模型 |
GET |
/models/default |
获取全局默认模型 | |
PUT |
/models/default |
更新全局默认模型 | |
GET |
/providers |
查询注册的 LLM 提供商 | |
GET |
/presets |
查询可用 Agent Preset 清单 | |
| Settings | GET |
/settings |
获取系统设置配置命名空间 |
PATCH |
/settings/:namespace |
更新指定命名空间配置 | |
| API Service | GET |
/api-keys/service |
独立服务状态(运行中 / 端口 / 监听范围 / 可访问地址) |
POST |
/api-keys/service/start |
启动或换端口、换监听范围(即时生效,失败回滚) | |
POST |
/api-keys/service/stop |
停止(保留端口,下次 DSH 启动不自动拉起) | |
GET |
/api-keys/service/free-port |
建议一个空闲端口 | |
GET / PUT |
/api-keys/port |
旧版兼容(fixedPort: 0 停止) |
|
| API Keys | GET |
/settings/api-keys |
API 服务与密钥设置页(HTML,公开;数据接口需 Admin Token) |
GET |
/api-keys |
列出 API Key(脱敏,不含明文/哈希) | |
POST |
/api-keys |
新建 API Key(返回明文,之后可随时复制) | |
PATCH |
/api-keys/:id |
修改名称 / 备注 / 过期时间 | |
POST |
/api-keys/:id/rotate |
轮换(旧 Key 立即失效,新 Key 可随时复制) | |
POST |
/api-keys/:id/reveal |
取回明文用于复制(需管理令牌;历史 Key 返回 409) | |
POST |
/api-keys/:id/revoke |
吊销(幂等,不可恢复) | |
DELETE |
/api-keys/:id |
删除记录(仅限已吊销的 Key) | |
GET |
/api-keys/auth |
查询鉴权状态 | |
PUT |
/api-keys/auth |
开启 / 关闭鉴权(关闭需 confirm: "disable-auth") |
|
| Docs | GET |
/docs |
内置交互式 API 测试页面 |
GET |
/docs/reference |
在线接口文档与调试(Swagger UI,全量接口 Try it out) | |
GET |
/openapi.json |
OpenAPI 3.0 接口定义 |
开发与构建
# 构建插件
bash scripts/build.sh
# 运行时热注入 (需 dsh-super-injector)
dev_inject_plugin {"dir": "/path/to/dsh-web-service"}
# 热重载
dev_reload_package {"packageName": "dsh-web-service"}
SKILL:让 AI 智能体学会调用本 API
本仓库自带一份 DSH 原生 SKILL(skills/dsh-web-service/SKILL.md),安装后 AI 智能体会自动发现并掌握全部接口的用法(触发词:HTTP 操作 DSH、三方集成、OpenAI 兼容调用等),会话内也可用 /dsh-web-service 直接调用。
一键在线安装(推荐)
curl -fsSL https://raw.githubusercontent.com/toddpan/dsh-webapi/main/scripts/install-skill.sh | bash
安装到用户级 skill 目录 ~/.dsh/skills/dsh-web-service/,DSH 的 skill-filesystem 提供方会热发现(无需重启),下一个会话即可用。
可选参数
# 安装到指定目录(项目级 .dsh/skills 或 .agents/skills)
curl -fsSL .../install-skill.sh | bash -s -- --dir /path/to/project/.dsh/skills
# 指定分支 / 仓库
curl -fsSL .../install-skill.sh | bash -s -- --branch dev
curl -fsSL .../install-skill.sh | bash -s -- --repo other/dsh-webapi
# 卸载
curl -fsSL .../install-skill.sh | bash -s -- uninstall
# 或本地:bash install-skill.sh uninstall
脚本行为:下载 SKILL.md → 校验 frontmatter 合法性 → 安装到目标目录 → 探测本机 3080/3000 端口的 DSH Web Service 是否在线并提示。幂等可重复执行。
本地安装(仓库内)
bash scripts/install-skill.sh
License
BSD-3-Clause
链接
同类插件
zhu1090093659/dsh-web#packages/dsh-remote-web-ui★ 9959
手机/PC 远程操控 dsh web 工作区:扫码配对、令牌门控通道、SSE 实时同步,提供移动端与完整桌面 GUI 两种远程形态。
zhu1090093659/dsh-web#packages/dsh-ssh★ 9959
SSH 远程运维面板:Web 终端、SFTP 传输、本地端口转发与一条命令并发集群执行,Agent 与面板共用同一份主机配置。
liguobao/ds-harness-remote★ 1319
通过端到端加密通道远程访问 DeepSeek Harness 及兼容的编码工作区,支持自适应 Relay/WebRTC 传输、设备授权、工作区文件、只读预览、终端和可选的 Codex Remote。
saya-ch/dsh-mobile★ 728
通过 Android App 或手机浏览器访问 DeepSeek Harness,支持安全局域网连接、远程访问、持久设备配对和可自定义移动界面。
uumit-ai/dsh-uumit-remote★ 381
用 UUMit 账号在手机或其他电脑上打开这台电脑的 dsh web,不用自建服务器、不装其他程序:插件内置通道客户端连接 UUMit 托管的通道,侧栏里的面板负责配对和选择谁能用(仅自己、通过邀请链接或手机号授权的人、所有人),可随时撤销。需 dsh web 且 DSH >=0.2.1-rc.2。
ZSeven-W/dsh-ios★ 355
在对话里直接操作 iOS 模拟器或 USB 连接的 iPhone:22 个 Agent 工具用于启动、构建、按无障碍标识或 OCR 文本驱动 UI、列表行操作与 SwiftUI 预览热重载,并附带可点击拖拽的流式侧边栏面板。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。