DeepSeek Harness 插件

omdsh-dev/dsh-genui

Star 数 ★ 483 下载量(近 30 天) 24,486 分类 UI 增强 收录于 2026-08-13 npm @changfenhuang/dsh-genui

助手回复内渲染交互式 UI 组件:布局、图表、表单、测验、mermaid、3D 场景与回传事件循环。

安装

# npm 包(预构建)

dsh plugin --profile web add @changfenhuang/dsh-genui

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:omdsh-dev/dsh-genui

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。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 · 简体中文

打开在线产品站 · 看真实演示 · 安装到 DSH

让模型的回答长出界面——文字还在,可交互的 UI 已经能用。

🔌 生态:仓库已挂 #dsh · #dsh-plugin topic,欢迎 @dsh-plugin 收录。

dsh-genui 把模型回答变成安全、可交互的 DSH 界面。你问「这个月订单怎么样」,回答除了文字,还可以直接带上可排序的数据面板、原生音视频、可拖动的函数图、本地判题或常驻会话面板。

先看真实证据

你想做什么 直接看这里 可以确认什么
先看完整 DSH 流程 40 秒真实录屏 组件确实出现在 DSH 的真实对话里。
看具体界面是什么样 三类真实输出 监控、函数绘图和可组合的布局组件。
立刻在自己的 DSH 里试 快速开始 npm 公开包安装、验证提示词与激活检查。
学会 JSON 界面描述 组件语法 受白名单约束的 dsh-ui 组件规范。

观看真实界面

不是概念图。 本节的录屏与截图均来自 dsh-genui 在 DSH 界面中的实际渲染;先看它真正长什么样,再决定是否安装。

40 秒完整演示

https://github.com/user-attachments/assets/f5db33ec-7471-4d4a-a85b-79c9962ab4ef

录屏依次经过回答内嵌面板、表单、函数绘图、Mermaid 与面向 3D 的组件。播放器不会自动播放;若没有加载,请打开原始 MP4,四幕提示词见 demo-prompts.md。

一条 DSH 回答里的三类真实输出

1. 监控面板就是回答的一部分,不是另开一个仪表盘
2. 改参数时,函数图在本地即时重绘
3. 布局原语可以组成有层级的工作界面

⚠️ 先看这里:双通道渲染(无需修改宿主源码)

本插件自带两套渲染通道;宿主激活浏览器模块后,插件会自动选择:

  • Registry 通道:宿主提供 fence-registry 扩展点(新版 dsh 构建)时,围栏经宿主流式渲染管线注册,行为与宿主无缝;
  • DOM 通道:宿主没有该扩展点(包括支持范围内的原版 DSH 构建)时,插件观察会话 DOM 自行挂载渲染树。自 0.7.2 起支持流式渲染:模型写到哪渲染到哪,首个完成的组件立即出现,不用等整段回复写完。自 0.8.3 起围栏发现多表面兼容:同时匹配标准 md-code-block 表面、部分宿主构建使用的 deepsuite 风格 .code-block / .code-block-small 表面,并以「label+<pre>」结构兜底——任何 banner 标注 dsh-ui 且含 <pre> 正文的元素都能被识别。即使你的 dsh 构建用了别的类名,围栏照常渲染(控制台会有一条一次性提示说明宿主 DOM 发生漂移)。
  • DSH 0.1.7 通用代码块:宿主最终 DOM 没有提供围栏 language metadata 时,dsh-genui 会从公开 ChatSnapshot 读取当前 assistant 的原始 Markdown,并且只接管 dsh-ui 围栏。DOM 负责确定挂载位置。source 数据暂时不可用时,assistant 已结束的通用 CodeBlock 才能通过严格的 canonical GenUI 规范校验进入最终兜底。

无论走哪条通道,组件、交互、面板、持久化行为完全一致。

CI 的 packed host smoke 会把实际生成的 npm tarball 安装到真实 DSH 宿主,并验证宿主启动与界面渲染。source-backed 围栏识别由 integration tests 覆盖;该 smoke 不代表真实模型回复验收。真实模型 E2E 需要配置模型凭据。

本仓库已经包含两条渲染通道、服务端插件和浏览器构建产物;宿主仍负责激活客户端模块,并提供 slots 与 sessions 服务。client.js 返回 200 或出现在 ModuleLoader 缓存里,只能证明文件下载成功;真正激活后一定会打印 [genui] client active; fence-channel=registry|dom。没有这行时应先核对包名/网页配置/宿主激活链,data-streaming、data-chat-anchor-key 等页面属性只是可选信息,不是安装前提。


✨ 装之前 vs 装之后

普通回答 装了 dsh-genui
"本月收入 ¥128,430,环比 +12.4%,建议关注转化率。" 一行分析 + 旁边直接渲染:收入/订单/转化率三张统计卡、趋势图、进度条
想再看别的?再打一段字问一遍 面板上就有「刷新」「切换视图」按钮,点一下,模型更新数据

🚀 快速开始

前置条件,缺一不可:

  1. dsh ^0.1.2-rc.1 || ^0.1.5-alpha.1 || ^0.1.6-alpha.1 || ^0.1.7-alpha.1(验收宿主标签为 dsh-v0.1.2-rc.1、dsh-v0.1.7-alpha.1 与 dsh-v0.1.7-alpha.2;使用 DSH <=0.1.1-rc.x 的用户请使用 dsh-genui 0.9.8)
  2. pnpm 在 PATH 上:dsh plugin 命令依赖它。没有就 corepack enable(或 npm i -g pnpm),然后新开一个终端,确认 pnpm -v 有输出

安装并在 DSH 中激活(一行命令,自动带上全部依赖):

# npm 公开包安装(无需 npm 账号)
dsh plugin --profile web add @changfenhuang/dsh-genui

如果只想把它作为 Node 依赖加入现有项目:

npm install @changfenhuang/dsh-genui

npm install 只添加依赖,不会把插件注册到 DSH;在 DSH 中使用时仍应执行上面的 dsh plugin add。

⚠️ 别用 link: 装一个刚 clone 的目录——link: 不会安装插件的依赖(mermaid / three / react),装完渲染器会挂。正常安装请使用上面的 npm 命令;只有本地开发迭代才用 link:(见下文)。

从旧 @omdsh-dev 包名迁移

如果你在 v0.9.2 之前通过 github:omdsh-dev/dsh-genui 安装过,pnpm 可能仍把依赖保存在旧的 @omdsh-dev/dsh-genui 键下,但仓库当前声明的包名已经是 @changfenhuang/dsh-genui。加载器按 profile 的依赖键解析插件,后续重装时就可能报 Cannot find package '@changfenhuang/dsh-genui'。请用当前包名重新添加一次:

dsh plugin --profile web remove @omdsh-dev/dsh-genui
dsh plugin --profile web add @changfenhuang/dsh-genui

这次迁移只针对改名前留下的 GitHub 源安装。此后新装统一使用上面的 npm 命令,并采用当前依赖键。

60 秒验证安装

命令完成后,重启 dsh web 并对浏览器硬刷新。在新会话中输入:

用 dsh-ui 画一个带可排序服务表的统计看板。

正常情况下,回答会原地变成仪表盘,而不是显示成代码块。想做最明确的技术确认时,打开浏览器控制台:成功激活会打印 [genui] client active; fence-channel=registry|dom。

开发者迭代(link 模式)

cd dsh-genui
pnpm install
dsh plugin --profile web add link:$PWD

🧩 能力地图

界面方向 第一次怎么试 可以直接观察到的行为
数据 让它做订单或服务监控看板 stat、table、chart、progress 直接出现;已支持的数值表格按数值排序。
媒体 让它引用一段音频或视频 浏览器可访问的媒体直接内嵌播放,带封面/比例和失败状态。
探索 让它用 plot 画带参数的函数 拖动滑块,本地立即重绘曲线。
反馈 让它出一道小测 判题和解析在本地完成;需要模型参与的下一步才使用 action。
工作区 使用 /panel 或 panel: true 常驻、可调高的会话 dock 在原地更新。

下面是完整能力说明。所有行为都受白名单 dsh-ui 规范约束;JSON 写法请看 SKILL.md。

  • 回答即界面:组件嵌在回答里,边生成边出现,不用等整段写完

  • 30+ 组件:卡片、表格、图表、表单、标签页、折叠面板、文件树、时间线、diff……

  • 原生音视频:浏览器可访问的 http(s) 或同源相对地址直接嵌入回答;用户主动控制播放,视频支持封面与画面比例,失败时原位提示

  • ECharts 集成:echart 节点渲染完整的 ECharts 图表,自动适配主题色、提示框和图例。两种模式:预设简写(preset: 'bar' | 'line' | 'area' | 'pie' | 'scatter' + data/series)可从 chart 节点快速升级;完整选项(option 字段)支持自定义图表类型、dataZoom、visualMap 等高级 ECharts 功能。echarts 引擎(~1 MB)按需懒加载——主包不含引擎,没有 echart 节点的对话不会下载它- 函数图:plot 画曲线,参数滑块拖动实时重绘,支持自动动画

  • 测验:quiz 点选判题 + 解析 + 重试;带 action 时答案同时回传模型(判题仍本地即时)

  • 本地判卷(交卷):多道选择题 = 每题的 radio 加 group + answer(正确答案)+ explanation(解析),再加一个 submit 交卷按钮——用户全部选完点一次,分数、每题对错、解析当场在 UI 里出现,零模型往返;题目随即锁定,「重新作答」本地重置(可选 resetAction 通知模型)。题目没带答案时才退回聚合 action(fields 收集所有带 id 的输入)

  • 状态持久化:答案、交卷锁定、输入值按「会话 + 内容指纹」自动保存——刷新页面/重开会话原样恢复,重渲染相同内容保留用户状态,新内容自动从头开始;上限 200 块 LRU 淘汰

  • 表单语义:input 回车 / textarea Ctrl+Enter 即时提交(submit:true),不用等失焦;带 id 的字段值进 submit 的 fields 收集

  • 秘密禁令:GenUI 不得索取密码、API Key、访问令牌、恢复码或其他秘密;密码输入即使出现也保持打码、不持久化、不进表单收集

  • 本地优先原则:UI 自己能完成的状态变化(判卷、判题、重置、展开、选中)一律本地即时完成;action 只用于必须模型参与的事(生成新内容、执行工具、下一步建议)

  • 诚实交互:交互组件必须带 action;不带 action 的按钮渲染为禁用态(消灭"看着能点、点了没反应"的假按钮);带 action 的按钮点击后立即显示「已触发」本地反馈(只证明本地事件已触发,不代表模型已收到)

  • 事件循环:按钮、复选框、单选、开关、下拉、输入、文本域、提交和测验等离散交互按一次手势一次事件立即回传模型;slider 连续拖动保留尾沿防抖,同一滑块只回传最终值,不同 id 的滑块互不合并。

  • 工具通道:render_ui 工具把同一份 spec 渲染成工具行卡片(交付物型 UI 走工具、回答型 UI 走围栏)

  • 会话面板:composer 上方常驻 dock,render_ui / panel: true 围栏原地更新同一块界面;/panel 命令客户端直开(/panel <指令> 转模型定制、/panel clear 清空);顶边框可拖拽调高;append: true 增量合并——同名标签页追加内容、新标签页新增;整面板默认最多 200 节点 / 200 条追加,达到上限后模型应发送 replace 重建

  • 围栏自修:默认开启;在 profile 的 cordis.patch.yml 中本插件条目的 config: 下设置 fenceFeedback: false 可以关闭。回答最终的 dsh-ui 围栏无法渲染时,插件借宿主的轮内转向(steer)把逐节点诊断送回同一轮,模型重发修好的围栏;每轮至多一次、每个围栏至多一次、子代理不触发,不会循环。

  • 自愈与上限:每个围栏过规格守卫——坏节点静默丢弃(同围栏其余组件照常渲染,单个坏组件不再拖垮整条围栏)、数值钳位、字符串截断,整树 ≤200 节点 / 8 层嵌套,病态 spec 不会拖垮界面

  • 统一组件协议:card.label → title、table.data/table.items → rows、callout.kind/callout.desc → tone/content(tone 值 danger → error)、steps.items → steps、keyvalue.items → pairs(记录内 label → key)、file-tree.nodes → items(记录内 label → name、有 children 时缺省 dir)等原生字段别名会在校验和渲染前确定性归一化;根级组件数组视为 items、双重编码的 JSON 字符串解一层;validate_dsh_ui 会报告归一化结果,并对原生组件未知字段给出警告,同时保持自定义 renderer 节点的透明兼容。

  • 图错误自愈:mermaid 渲染失败自动修复重试(剥反引号、引号化中文/空格标签、去 <br/>),仍失败才降级源码;错误图永不直接上屏

  • 可访问性:tabs/折叠/开关/进度条带完整 ARIA 与键盘导航(方向键切页、Home/End 跳转)

  • 零打扰:不装插件时围栏只是代码块,不报错、不污染会话

🏆 新手引导:模板中心与探索成就(0.9.4+)

  • 模板中心:会话面板 dock 顶部的「模板」按钮——11 个分类示例(仪表盘/方案对比/上手流程/随堂测验/趋势图/标签页/清单/FAQ/架构图/3D/文件树),点击即内嵌预览(示例由 GenUI 本身渲染),「试用」一键把指令插入输入框、发送即让模型生成;「复制指令」可带走。
  • 探索成就:同一 dock 的「成就」按钮——12 个成就(初次相见 → 蓝图之魂),按渲染/交互/面板/模板埋点计数,解锁弹 toast,成就页由 dsh-ui 渲染自己的列表;只存计数(localStorage),绝不读取消息内容;隐藏成就(传说)解锁前显示「?」。
  • 首次提示:第一块面板出现时显示 6 秒一次性提示(指向「模板」按钮),不打扰式引导。

组件 JSON 语法见 SKILL.md。宿主提供公开 skill registry 时,插件会自动注册内置 genui skill,因此新会话无需向 ~/.dsh 复制文件即可获得完整组件与字段目录。

chart 保持三种图形的紧凑渲染器:使用 kind: 'bars' | 'line' | 'donut',且 data[].value 必须是有限数字。validate_dsh_ui 会明确报告误用的 variant、不支持的 kind 和非法数据字段;render_ui 对同样错误直接失败,不再静默渲染默认柱图。未知扩展字段仍允许存在。

📄 示例

模型输出这段围栏(写给浏览器看的,你不用读懂):

{"title":"订单概览","items":[
  {"type":"stat","label":"总收入","value":"¥128,430","delta":"+12.4%"},
  {"type":"stat","label":"订单数","value":"1,024","delta":"-3.1%"}
]}

你看到的是两张统计卡片。

ECharts 示例

{"title":"Q1 收入","items":[
  {"type":"echart","title":"月度收入","preset":"bar","data":[
    {"label":"1月","value":98},
    {"label":"2月","value":112},
    {"label":"3月","value":128}
  ]}
]}

你看到的是一张带提示框和坐标轴的主题色柱状图——由 ECharts 渲染,按需懒加载。

🔧 原理

模型把界面描述写成 JSON 放进 dsh-ui 围栏,浏览器端渲染器(src/client)通过主仓 fence-registry 接口认领这门语言并渲染。组件是白名单的,模型塞不进 HTML/脚本;函数表达式走独立解析器,不用 eval。

主渲染包保持轻量(≈110 KB min / 28 KB gzip),mermaid、three.js 与 echarts 引擎单独打包为按需资产(首次用到时经插件自注册的 HTTP 路由加载),启动时只下载渲染核心。

❓ 常见问题

  • 显示成代码块? 先在浏览器控制台找 [genui] client active; fence-channel=registry|dom。没有这行,即使 client.js 返回 200,也只是下载了文件、没有激活:请对齐网页配置依赖名、package.json.name、cordis.patch.yml、ModuleLoader id 和配置中的 bundle 名。出现这行后再查围栏标签/正文;宿主没有 registry 时会自动走 DOM 通道。
  • 渲染 dsh-ui fence 时聊天界面白屏? 此版 dsh-genui 要求 DSH ^0.1.2-rc.1 || ^0.1.5-alpha.1 || ^0.1.6-alpha.1 || ^0.1.7-alpha.1;使用 DSH <=0.1.1-rc.x 的用户请使用 dsh-genui 0.9.8。
  • dsh: pnpm not found on PATH? 装 pnpm 后新开终端再试(corepack enable 或 npm i -g pnpm)。
  • npm 安装返回 404? npm 包是公开的,无需登录。先执行 npm view @changfenhuang/dsh-genui version 核对包名与公共 registry;若新版本刚发布仍返回 404,稍后重试。
  • 装了但 scene3d/mermaid/echarts 不渲染? 引擎(mermaid / three / echarts)不再内联进 client.js——它们在首次用到时按需加载(/plugins/@changfenhuang/dsh-genui/assets/*.js,插件自带 HTTP 路由托管)。先重启 dsh web + 硬刷新(Cmd+Shift+R);仍不渲染就卸掉重装(dsh plugin --profile web remove @changfenhuang/dsh-genui 后再 add)。旧版宿主缺少资产路由时会降级显示源码/加载失败提示,更新 dsh 即可。
  • 模型不主动输出? 重启后新会话生效;或直接说"用 dsh-ui 输出"。
  • clone 后没有 lib/? pnpm install && pnpm run check 自己构建。

🧑‍💻 开发

嵌入其他应用

支持 CSS Modules 和 TypeScript 的浏览器构建器可以从 @changfenhuang/dsh-genui/embed 导入 GenuiBlock、GenuiActionContext、ErrorBoundary 和 processGenuiSpec,复用同一份组件、样式与规格校验,无需加载 DSH 的插件入口。

嵌入宿主通过 initialState / onStateChange 接管持久化,使用稳定的 stateKey 区分界面,通过 GenuiActionContext.Provider 接收动作。改变 stateKey 会开始新的交互生命周期;同一界面的后续刷新保留输入。设置 onStateChange 后不读写浏览器的交互状态存储。

调用 setGenuiAssetBase 设置本地引擎目录;从公开的 @changfenhuang/dsh-genui/assets/mermaid、assets/three、assets/echarts-core、assets/echarts 构建对应脚本。模型指引从 @changfenhuang/dsh-genui/skill 读取。宿主只补自己的交付通道和设计变量;渲染器仍使用本包与 @deepseek-ai/dsh-client-ui-primitives 的组件。构建时提供 React、CSS Modules、KaTeX 字体及所用引擎依赖。

导出 GenUI 成果文件

已完成的 GenUI 区块提供“导出 → HTML”和“GenUI JSON”。.html 文件内含渲染器、样式、KaTeX WOFF2 字体和规格实际需要的图形引擎,本地控件可以继续使用,模型动作按钮会禁用。相对媒体地址会按导出页面的地址转换为绝对地址;离线打开时,网络媒体仍需连接原站点。.genui.json 保留原媒体地址、规范化规格、可持久化交互状态、语言和主题。自定义组件会禁用 HTML 导出,导出错误会显示在菜单旁。宿主可从 @changfenhuang/dsh-genui/embed 使用 createGenuiArtifact、parseGenuiArtifact、serializeGenuiArtifact 和 buildStandaloneHtml;@changfenhuang/dsh-genui/assets/standalone 指向可供复制或提供下载的运行文件。

pnpm install
pnpm run check   # 类型检查 + 全量测试 + 构建

安装锁定依赖后,检查脚本(pnpm run check 或 npm run check)使用固定的 DSH 0.1.2-rc.1 发布包。

pnpm run check:host-api dsh-v0.1.7-alpha.1 与 pnpm run check:host-api dsh-v0.1.7-alpha.2 会在隔离目录安装对应的 DSH npm 发布包,运行 TypeScript 类型检查与 tsdown 构建。CI 对两个版本执行检查,然后运行安装包宿主 smoke 测试。

运行 node scripts/verify-pack.mjs --keep 可保留已验收的 tarball,便于检查或运行 e2e;默认的 node scripts/verify-pack.mjs 会在验收后清理临时目录。

真机 e2e

真实链路验证:起一个临时 dsh web → 装上插件 → 浏览器里发消息让模型输出 dsh-ui fence → 断言渲染 → 点击 action 按钮 → 断言模型响应(事件循环闭环):

export DSH_ROOT=/path/to/deepseek-harness-0.1.2-rc.1
export DSH_BIN="$DSH_ROOT/apps/cli/lib/bin.js"
DEEPSEEK_API_KEY=sk-... node scripts/e2e.mjs          # link 安装当前工作区

先构建 DSH 0.1.2-rc.1 checkout。按上面的示例将 DSH_ROOT 指向该 checkout,将 DSH_BIN 指向其中的 apps/cli/lib/bin.js;另需准备 pnpm、DEEPSEEK_API_KEY 和主仓 web 构建产物。PASS 时保存 e2e-final.png 截图。

视觉 e2e(无需模型 key)

样式/组件迭代用:使用 DSH 0.1.2-rc.1 checkout 起真实 dsh web + link 安装插件 → 通过 DOM 通道注入组件画廊围栏 → headless Chrome 全页截图 + 本地交互(表格排序 / 判题 / 目录折叠 / 数值对齐)硬断言,不需要任何模型额度。运行前按上面的示例将 DSH_ROOT 和 DSH_BIN 指向该 checkout:

npx tsx scripts/e2e-visual.mts          # → .e2e-artifacts/gallery.png + interactions.png
npx tsx scripts/e2e-visual.mts --keep   # 保留 scratch DSH_HOME 便于排查

可覆盖:--port 3098、--out <dir>、DSH_BIN(设为 DSH 0.1.2-rc.1 checkout 内的 apps/cli/lib/bin.js)、PLAYWRIGHT_PATH(默认全局 playwright-core)。

🗺️ Roadmap(已评估项)

方向 结论 理由
增量 patch(模型只发 diff 不重发全量 spec) 不做 fence 一次 200–800 token,重发代价极小;patch 协议的教学成本与出错率不值得。若未来出现秒级自动刷新面板再议
action 回传 ✅ 离散交互立即回传;slider 拖动按 action 和 id 防抖 离散操作逐次回传,slider 拖动只回传最终值
跨会话状态持久化(回放恢复 tabs/开关) 不做 回放重置是更正确的默认行为(模型已用新 fence 更新过界面);流式期间状态天然保留
MCP 适配器 / 独立画廊页 / i18n 不做 无跨工具需求信号;画廊素材已被 gallery.ts + demo-prompts + README 截图覆盖;内置文案仅 6 处

🔗 友情链接


📄 License: MIT

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →

社区评论

评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。