dsh-graphics
English | 中文
DeepSeek Harness(DSH)插件:工作区内的 Excalidraw 画布,让 Agent 能画图、读图,并把渲染出来的图直接交给模型看。
状态:v0.1.0 功能完成。5 个 Agent 工具已在 live 会话注册并对模型可见, 渲染图能作为图像内容块回传给模型(M1 / M3 已过真机验收);Excalidraw 编辑面板已落地并按真机反馈迭代。 全量 64 项测试通过(smoke 25 / render 10 / render-tool 13 / integration 16)。 见
docs/plan.md。

它解决什么问题
DSH 里让模型产出"图"的常见做法是生成 SVG / Mermaid 文本,模型自己看不到结果,用户也得另找工具打开。 dsh-graphics 换一条路:
- 画布是工作区里的普通文件(
.excalidrawJSON),模型能用现有文件工具读、能进 Git、能随项目走; - Agent 有专门的画图/读图工具,不必手写底层元素 JSON;
- 渲染图直接作为图像内容块回传给模型,模型在下一轮就能"看见"自己画的东西并自我修正;
- 导出 SVG 落地到工作区,供用户使用或作为交付物(PNG 只走附件服务,见「已知限制」)。
能力
Agent 工具
| 工具 | 作用 |
|---|---|
graphics_list |
列出工作区内的画布 |
graphics_read |
读画布:结构化摘要(页面/元素/文字/关系),而非整份元素 JSON |
graphics_create |
从语义化描述创建画布 |
graphics_update |
对已有画布做批量增删改 |
graphics_render |
渲染并把图回传给模型;可选把 SVG 导出到工作区 |
界面
在 DSH Web 里提供一个 Excalidraw 编辑面板:打开工作区中的 .excalidraw 文件、直接编辑、手动保存回原文件(带版本冲突保护)。
目录结构
dsh-graphics/
├── package.json # DSH 插件清单:dsh.bundle.patch + dsh.client
├── cordis.patch.yml # 把插件插进 profile 的补丁层
├── lib/
│ ├── index.mjs # 宿主侧:工具注册 + 静态资源路由
│ ├── scene.mjs # 画布文件读写与校验
│ ├── render.mjs # scene → SVG → PNG(无浏览器)
│ ├── render-tool.mjs # graphics_render:渲染 + 图像回传
│ ├── editor-assets.mjs # 伺服 editor/dist + 画布读写 HTTP API
│ ├── tools.mjs # defineTool 定义
│ └── client.js # 浏览器侧:Excalidraw 编辑面板
├── editor/ # 打包好的 Excalidraw 前端静态资源(由宿主伺服)
├── tests/ # smoke / render / render-tool / integration,共 64 项
├── examples/ # 真机验收产物(画布 + 渲染/导出的 SVG、PNG 预览)
├── tools/
│ └── asar-extract.mjs # 从 app.asar 里提取 DSH 实现代码与类型定义(开发期侦察用)
├── docs/
│ ├── design.md # 设计:架构、工具 schema、数据模型、安全边界
│ ├── plan.md # 开发计划与验收标准
│ ├── research.md # 调研事实清单(含出处与已验证结论)
│ └── host-integration-notes.md # 本部署的宿主侧坑与硬约束
└── AGENTS.md # 给后续 agent 的工作指引
关于 tools/asar-extract.mjs
DSH 的官方包(@deepseek-ai/*)打包在 /Applications/DeepSeek Harness.app/Contents/Resources/app.asar
里——那是个归档文件,不是目录,ls / cat / ripgrep 都打不开。这个小脚本能按路径正则把里面的
实现代码与 README.zh.md 提取出来,是解决 docs/design.md §9 那些待定问题的工具:
bun tools/asar-extract.mjs \
"/Applications/DeepSeek Harness.app/Contents/Resources/app.asar" \
"$TMPDIR/dsh-api" \
'dsh/node_modules/@deepseek-ai/dsh-fs/(README\.zh\.md|package\.json|.*\.d\.ts)$'
注意:asar 里不含
.d.ts。精确的类型定义要去 npm 取同版本的发布包 (registry.npmjs.org/@deepseek-ai/<pkg>/-/<pkg>-0.2.0-rc.2.tgz)。
安装
# 由 DSH 的 plugin_manager 完成,不要手写 profile 的 package.json
plugin_manager install_bundle target=/Users/juergenie/Projects/Workspaces/dsh-graphics
清单里已声明
dsh.client(lib/client.js与editor/dist/构建产物都已就位),加载后会注册 右侧栏画布标签页。反过来,在构建产物存在之前不要声明dsh.client——Web 启动审计会明确报 「激活失败」。这是从dsh-plugin-chat-mode的AGENTS.md里学到的教训("别声明不存在的能力")。
相关文档
用法
给 Agent 用
graphics_list 列出工作区里的画布
graphics_create path=… elements=[…] 画一张画布(语义化元素,不用写底层 JSON)
graphics_read path=… 读回结构摘要(含容器的绑定标签)
graphics_update path=… ops=[…] 批量增删改,一次落盘
graphics_render path=… ★ 渲染并把图**直接交给模型看**
graphics_render 是核心:它把 PNG 经 attachments.saveImage() 登记后,
以 {type:'image', attachment} 内容块回传,模型在下一轮就能看见自己画的东西。
带 outputPath 时还会把 SVG 导出到工作区(PNG 不行——ctx.fs 的变更操作是 UTF-8 文本专用)。
给人用
在 DSH Web 的文件树里点开任意 .excalidraw 文件,右侧栏会出现 Excalidraw 编辑器。
编辑器不做自动保存——画原型时频繁写盘既吵又危险(手一滑就覆盖了上一版)。 改动只在本地累积,标签页顶部工具栏显示「有未保存的改动」;点保存才落盘, 并有版本冲突保护(文件被 Agent 改过时会拒绝覆盖而不是静默丢失)。
工具栏另一个按钮是引用到输入框:点一下把当前画布的路径插进会话输入框,
于是 Agent 下一轮就能用 graphics_read / graphics_render 看到它——人和模型共用同一张画布。
输入框的 + 按钮(与键入 / 打开同一个菜单)里还有一条画布命令:
点一下就新建一张 graphics/canvas-<时间戳>.excalidraw 并在编辑器里打开,用来随手画点东西。
构建
pnpm install
pnpm build:editor # vite build + 拷贝 Excalidraw 字体到 editor/dist
pnpm test # 64 项测试(画布模型 / 渲染 / 图像回传 / 模拟宿主集成)
editor/dist/ 是构建产物(约 21MB,其中 13MB 是字体),不进版本库;
分发时由 package.json 的 files 带上。
已知限制
- PNG 不能导出到工作区:
ctx.fs的变更操作只支持 UTF-8 文本 (dsh-fsREADME:「二进制安全的变更操作仍延期」)。PNG 走附件服务, 以图像交给模型,并返回附件库的真实宿主路径;落盘用 SVG。 - 宿主侧代码改动必须重启 DSH:profile 下 HMR 不监听源码模块。见 docs/host-integration-notes.md §2。
- 编辑器 iframe 不继承宿主主题 token,初始主题取系统偏好(Excalidraw 自带主题开关)。
No comments yet. Be the first to write one.