把 OpenMAIC 带进 DeepSeek Harness —— 一个让 AI 助手能 "上课、出幻灯片、做互动小游戏、随手画教学卡片" 的插件。
dsh-openmaic(全名 @openmaic/dsh-openmaic,当前版本 0.4.0)是一个 DeepSeek Harness(简称 dsh)插件。它把清华开源项目 OpenMAIC(AI 智能课堂平台,线上服务在 open.maic.chat)的能力接进了 dsh 这个 AI 智能体框架里,让 AI 助手不再只会 "打字回复",还能直接生成课堂、渲染幻灯片、制作可交互的教学组件、画出教学卡片。
DeepSeek Harness 就像一个 "AI 操作系统",它有一套机制让各种 "外挂能力"(插件)可以插进来。
dsh-openmaic 就是插在这个系统上的一个 "教学能力包"。
装上之后,你对 AI 说 "帮我做一节量子物理课",它就能真的生成一个可以点开上课的网页课堂;说 "画一张力的分解示意图",它就能在聊天框里就地渲染出一张幻灯片。
| 项目 | 内容 |
|---|---|
| 包名 | @openmaic/dsh-openmaic |
| 版本 | 0.4.0 |
| 许可证 | MIT |
| 入口文件 | lib/index.js(编译产物,随插件分发) |
| 源码位置 | src/(TypeScript 编写) |
| 技术底座 | DeepSeek Harness(dsh)+ Cordis 插件框架 |
| 官方安装源 | git+https://github.com/THU-MAIC/dsh-openmaic.git |
"所有能力都是插件" —— 这是 dsh 的核心哲学。本插件把 "生成课堂、渲染幻灯片、渲染互动组件、渲染教学卡片、苏格拉底式教学" 这五件事,全部以 ** 工具(Tool)+ 技能(Skill)+ 界面组件(Toolview)** 的形式贡献给 dsh,即插即用、互不干扰。
装上这个插件后,AI 助手会获得 4 个工具 和 4 个技能:
| 工具名 | 干什么 | 典型用法 |
|---|---|---|
openmaic_generate |
把一个教学需求提交给 open.maic.chat,异步生成一整套可播放的在线课堂,返回课堂链接 | 用户:"帮我做一节量子物理入门课" |
openmaic_render |
把 AI 手写的一小段内联 HTML(概念卡、小测验、步骤讲解)渲染成聊天框里的沙箱卡片 | 用户:"用卡片解释一下什么是光合作用" |
openmaic_widget |
把 AI 手写的完整交互组件 HTML(模拟器 / 小游戏 / 代码练习)渲染成可交互的沙箱卡片 | 用户:"做一个抛体运动模拟器" |
openmaic_slide |
把 AI 写的 OpenMAIC 幻灯片 JSON(PPT 风格的页面)渲染成一页幻灯片 | 用户:"把这几个要点做成一张幻灯片" |
| 技能名 | 作用 |
|---|---|
openmaic-render |
教 AI 怎么写 "教学卡片" 的 HTML 片段(格式、尺寸、样式类、范例) |
openmaic-widget |
教 AI 怎么写 "互动组件" 的完整 HTML(带 3 种模板:模拟器 / 游戏 / 代码) |
openmaic-slide |
教 AI 怎么写 "幻灯片" 的 JSON(画布规格、元素类型、排版规则) |
openmaic-teach |
把一次对话变成苏格拉底式教学:一步步引导提问,配合上面工具做教学辅助 |
简单记忆:
工具 = AI 的 "手"(做什么)
,
技能 = AI 的 "说明书"(怎么做、按什么规范做)
。AI 在第一次调用某个工具前,会先读取对应的技能规范。
用户:帮我做一节量子物理入门课
AI → 调用 openmaic_generate(requirement="量子物理入门课", language="zh-CN")
← 得到: Classroom ID: class-abc123
Classroom URL: https://open.maic.chat/classroom/class-abc123
AI → 展示给用户: 课堂已经生成好了,点开就能上课:
https://open.maic.chat/classroom/class-abc123
用户:做一个抛体运动模拟器
AI → 按 openmaic-widget 模板边写边流式输出完整 HTML
→ 调用 openmaic_widget(html="<!doctype html>…", widgetType="simulation", title="抛体运动")
→ 聊天框里就地出现一个可拖动、可交互的抛体运动模拟器
这个插件在 dsh 里分成两个 "半边"工作,再加上一段共享契约和一个外部服务:
┌─────────────────────────────────────────────────────────────────┐
│ DeepSeek Harness(dsh) │
│ │
│ ┌──────────────────────┐ ┌───────────────────────────┐ │
│ │ Node 端(服务端半边) │ │ 浏览器端(UI 半边) │ │
│ │ │ │ │ │
│ │ 注册 4 个工具 │ ──────► │ OpenmaicCard(教学卡片) │ │
│ │ 注册 4 个技能(资产目录) │ meta │ WidgetCard(互动组件) │ │
│ │ 注入 4 段系统提示 │ 传递 │ SlideCard(幻灯片) │ │
│ │ openmaic_generate │ │ StreamingWidgetPreview │ │
│ │ 的 API 客户端 │ │ (写代码时实时预览) │ │
│ └──────────────────────┘ └───────────────────────────┘ │
│ │ ▲ │ │
│ │ │ 轮询作业 │ 沙箱 iframe │
│ ▼ │ ▼ │
│ ┌──────────────────────┐ ┌───────────────────────────┐ │
│ │ 共享契约模块(纯函数) │ │ 沙箱渲染(iframe+CSP) │ │
│ │ fragment/slide-meta/ │ │ 只有内联脚本+白名单 CDN │ │
│ │ widget-meta │ │ 不联网、不访问宿主页面 │ │
│ └──────────────────────┘ └───────────────────────────┘ │
└─────────────────────┬─────────────────────────────────────────────┘
│ HTTP(生成课堂)
▼
┌─────────────────────────┐
│ OpenMAIC 服务 │
│ open.maic.chat │
│ (异步生成可播放的课堂) │
└─────────────────────────┘
| 部件 | 位置 | 职责 |
|---|---|---|
| Node 端 | src/index.ts、src/tool.ts、src/widget.ts、src/slide.ts、src/client.ts、src/skill.ts |
跑在 dsh 的 Node 进程里,负责注册工具、注册技能、注入系统提示、发起 HTTP 请求(课堂生成) |
| 浏览器端 | src/client/* |
跑在网页 UI 里,负责把工具返回的内容渲染成漂亮的交互卡片 |
| 共享契约模块 | src/fragment.ts、src/slide-meta.ts、src/widget-meta.ts |
纯函数、不碰 I/O 和 DOM,Node 端、浏览器端、测试三方共用同一套校验逻辑 |
| OpenMAIC 服务 | 外部(open.maic.chat) | 只有 openmaic_generate 会调用它;其余三个工具都在本地渲染,不上传任何内容 |
openmaic_render 为例)用户在对话框提出需求 → AI 判断适合用教学卡片。
AI 先加载 openmaic-render 技能,拿到 "怎么写片段" 的规范。
AI 按规范写好一小段内联 HTML,调用 openmaic_render 工具,把 fragment 作为参数传入。
Node 端校验片段(非空、≤256KB、不得包含文档骨架标签)。
校验通过后,Node 端把片段写入持久化的 tool/result meta,返回一行简短确认文字给 AI(避免把大段 HTML 再喂回上下文浪费 token)。
浏览器端监听到该工具的调用,用 OpenmaicCard 组件把 meta 里的片段包进沙箱 iframe,在聊天框就地渲染成卡片。
因为内容来自持久化 meta,回放历史对话时卡片能一模一样地重现(replay-stable)。
openmaic_widget/
openmaic_slide的过程类似,只是渲染的组件不同。
openmaic_generate —— 生成整套在线课堂把教学需求变成一整套可点开上课的 AI 课堂(含讲解、互动、测验的网页)。这是唯一一个调用外部服务(open.maic.chat)的工具。
参数:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
requirement |
✅ | string | 要教什么,自然语言描述,如 "量子物理入门课" |
language |
否 | enum | 生成课堂的语言:zh-CN 或 en-US |
enableWebSearch |
否 | boolean | 是否允许生成管线联网搜索最新资料 |
enableImageGeneration |
否 | boolean | 是否生成配图 |
enableVideoGeneration |
否 | boolean | 是否生成视频 |
enableTTS |
否 | boolean | 是否启用课堂 Agent 的语音朗读 |
agentMode |
否 | enum | 生成模式:default 或 generate |
工作流程(异步作业 + 轮询):
如果配置了 accessCode(邀请码):先 POST /api/access-code/verify 验证,把返回的 openmaic_access Cookie 记下来,后续请求带上。
POST /api/generate-classroom,提交需求(只提交用户确实要求的可选开关),得到 jobId 和 pollUrl。
按 pollIntervalMs 间隔轮询 pollUrl,直到:
succeeded(成功)→ 返回课堂 ID + 可播放的课堂链接;
failed(失败)→ 报错并带上 jobId 和原因;
超过 maxWaitMs(默认 10 分钟)→ 提示 "仍在后台生成,稍后再查"。
返回给 AI 的格式:
Classroom ID: class-abc123
Classroom URL:
https://open.maic.chat/classroom/class-abc123
注意事项:
课堂生成很慢,官方建议把 pollIntervalMs 调大到 60000(60 秒)更友好。
只有用户明确要求才传可选开关;默认只传 requirement。
openmaic_render —— 渲染教学卡片把 AI 手写的一小段内联 HTML 片段渲染成聊天框里的卡片。适合:概念讲解、小测验、算法 / 多步过程逐步讲解、简易图示。
参数:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
fragment |
✅ | string | 内联 HTML 片段(只能有标签 + <style> + 可选 <script>,禁止 <!doctype>/<html>/<head>/<body>) |
title |
否 | string | 卡片标题,默认 "OpenMAIC 课堂" |
校验规则(写错会被工具报错拒绝):
片段不能为空;
大小不能超过 256 KB;
不能包含文档骨架标签(<!doctype>、<html>、<head>、<body>)—— 因为卡片会自己提供文档骨架和 CSP,嵌套会导致渲染错乱。
写作要点(技能会教 AI):
所有数据内联进片段(沙箱不联网),大数据先降采样;
使用内置样式类(card、btn、viz-grid、viz-row、viz-stat 等)自动继承宿主主题;
自带判分的小测验:判分逻辑写在 <script> 里本地完成,不把答题结果回传模型。
openmaic_widget —— 渲染互动组件把 AI 手写的完整 HTML 文档(模拟器 / 小游戏 / 代码练习)渲染成沙箱卡片。这是三种里最 "重"、最 "好玩" 的一个。
参数:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
html |
✅ | string | 完整 HTML 文档(<!doctype html> 到 </html>) |
widgetType |
否 | enum | simulation(模拟器,默认)/ game(游戏)/ code(代码练习) |
title |
否 | string | 组件标题,默认 "OpenMAIC 课堂" |
三种组件类型:
| 类型 | 用途 | 对应模板 |
|---|---|---|
simulation |
可交互画布:物理、系统、过程模拟 | assets/widget-templates/simulation.md |
game |
带计分 / 成就的小游戏(物理动作类、拖拽拼图、卡片配对等) | assets/widget-templates/game.md |
code |
可运行的代码练习(Python/JS/TS,带测试用例) | assets/widget-templates/code.md |
特色功能:
流式预览:AI 还在写代码时,聊天输入框下方就会实时显示正在生成的 HTML(StreamingWidgetPreview 组件 + extractStreamingWidget 从不完整的 JSON 里边写边解析)。
LaTeX 转 KaTeX:工具会把 HTML 里的 LaTeX 后处理成 KaTeX 可渲染格式。
展开按钮:模拟器和游戏在聊天栏里可能不够大,卡片右上角有 "⛶ 展开" 按钮,可全屏 / 大窗体验。
openmaic_slide —— 渲染幻灯片把 AI 写的 OpenMAIC 幻灯片 JSON(PPT 风格的单页)渲染成一页幻灯片。支持文本、图形、连线、图片、表格、图表、公式(LaTeX)、代码等元素。
参数:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
slide |
✅ | object | 幻灯片 JSON:必须有非空 elements 数组,background 可选 |
title |
否 | string | 标题,默认 "OpenMAIC 幻灯片" |
工具替你做的事:
固定画布:无论 AI 怎么写,画布统一为 1280 × 720(16:9),AI 写不出错误的几何尺寸;
默认主题:如果 AI 没给主题,用内置的默认主题(白底 + 一套图表配色);
补全 ID:没写 id 时自动生成。
元素类型一览(来自 slide 生成契约):
| 类型 | 作用 |
|---|---|
text |
文本(HTML 内容),高度必须查官方 "高度速查表" |
shape |
矩形 / 圆形等矢量图形(SVG path) |
line |
直线 / 箭头 / 折线 / 曲线(注意 width 是线宽不是长度) |
image |
图片 |
table |
表格(单元格文本是纯文本,不支持 LaTeX) |
chart |
图表(bar/column/line/pie/ring/area/radar/scatter) |
latex |
LaTeX 公式(KaTeX 渲染,自动按比例缩放) |
code |
代码块 |
排版规则要点(契约里非常详细):
一页只放少量元素,别做成密集的整套 PPT;
元素按数组顺序叠加,背景图形放前面;
每个元素要有唯一字符串 id;
文本每行 ≤ ~20 词(中文 ≤ ~30 字);
公式要用专门的 latex 元素,严禁把 LaTeX 写进文本元素(会原样显示反斜杠)。
技能是打包进插件的(bundled),模型可调用、用户也可调用。它们的正文存放在 assets/ 目录。
openmaic-render —— 教学卡片写作规范告诉 AI 怎么写 "仅内联片段"(不要文档骨架);
数据必须内联(沙箱断网);
大小上限 256KB;
推荐使用内置样式类 card / btn / viz-grid / viz-row / viz-stat 等;
带判分的小测验在本地 <script> 完成,不回传模型;
附最小示例和测验示例。
openmaic-widget —— 互动组件写作规范定义 3 种组件类型(simulation /game/code)并指向对应模板;
硬性要求:
输出恰好一个完整 HTML 文档(<!doctype html> 到 </html>),不许套 markdown 代码块;
嵌入 <script type="application/json" id="widget-config"> 描述组件;
必须包含 postMessage 监听器(SET_WIDGET_STATE / HIGHLIGHT_ELEMENT / ANNOTATE_ELEMENT / REVEAL_ELEMENT),方便将来 "教学代理" 驱动组件;
元素命名规范:{变量}-slider、{动作}-btn、{变量}-display;
移动端适配、触控目标 ≥ 44px、有明确的运行 / 结束状态。
三个模板(
simulation.md/
game.md/
code.md)非常详尽,包含了大量 "常见坑": 重置按钮必须真的重置所有状态; 模拟器必须有
肉眼可见的动画
(不是只变个数字); 游戏
不能开局就失败
(前 3-5 秒安全期 + 合理初值); 代码练习用 Pyodide 时,必须
import sys和
import io才能捕获输出,且用
runPythonAsync; 游戏开始按钮用
内联 onclick
(比 addEventListener 可靠); 不要用 Tailwind CDN 的
@layer utilities(可能编译失败)。
openmaic-slide —— 幻灯片写作规范画布固定 1280 × 720,边距 ≥ 50;
输出结构:{ "background": {...}, "elements": [...] },elements 必填且非空;
元素类型和字段遵循 assets/slide-template/system.md(官方 slide-content 生成契约);
文本高度必须查 "高度速查表"、宽度按公式校验、居中要对齐到 <2px;
幻灯片是视觉辅助不是讲稿:禁止把 "老师说的话" 写上去(不能出现 "老师提醒你…" 这类个人化内容)。
openmaic-teach —— 苏格拉底式教学把当前会话变成 "引导式教学":
摸底:先问用户对这个主题已了解多少,据此调整起点;
切块:把主题拆成 3-6 个小步骤;
每步循环:先提问 → 等用户尝试 → 卡住就给提示 / 更小的子问题 → 确认或纠正 → 等用户真正接触概念后再用一张视觉辅助 "确认"(而不是 "剧透");
小测验:一个简短的自判小测验确认理解;
总结:用用户自己的话复述思路链。
辅助工具的使用原则:
概念是 "事实 / 结构" 型 → 用 openmaic_slide(定义、公式、标注图、对比);
概念是 "动态 / 过程" 型 → 用 openmaic_widget(模拟、机制、可运行示例);
只需小视觉 → 用 openmaic_render(概念卡、小测验);
只有用户明确要整套课 → 才用 openmaic_generate;
先问后展示:辅助图是在学习者 "思考过之后" 用来确认的,不是用来提前泄题的。
在 dsh 环境里执行:
dsh plugin --profile web add git+https://github.com/THU-MAIC/dsh-openmaic.git
然后重启 dsh web 并刷新页面。
插件
**自带编译好的 **
lib/** 目录**
,所以通过 git 安装
不需要再构建
,装上就能用。
dsh-openmaic:
baseUrl: https://open.maic.chat
accessCode: "" # 邀请码;线上暂未强制,留空即可
pollIntervalMs: 5000
maxWaitMs: 600000
| 配置项 | 默认值 | 说明 |
|---|---|---|
baseUrl |
https://open.maic.chat |
OpenMAIC API 地址。想对接本地 OpenMAIC 实例可改成 http://localhost:3000 |
accessCode |
"" |
open.maic.chat 的邀请码。线上尚未启用,留空;启用后再填 |
pollIntervalMs |
5000 |
课堂生成作业的轮询间隔(毫秒)。生成很慢,建议调到 60000 |
maxWaitMs |
600000 |
单个作业最长等待时间(毫秒),默认 10 分钟 |
所有由 AI 生成的内容(卡片、组件、幻灯片)都在受限的沙箱里渲染,这是本插件最看重的设计之一:
<iframe sandbox="allow-scripts">:只允许脚本运行;iframe 是 opaque origin(与宿主页面完全隔离),里面的脚本无法访问 dsh 页面本身。
自带的 CSP(内容安全策略):每个卡片文档都带一个强 CSP:
只允许内联脚本 / 样式 + 白名单 CDN(cdnjs、jsdelivr、esm.sh、Google Fonts、unpkg 等);
禁止网络请求(connect-src 只允许 blob:/data:,不能 fetch/XHR/WebSocket);
禁止嵌套 iframe、禁止表单提交、禁止 base 标签篡改、**禁止 **object。
即使 AI 生成的 HTML 里夹带了恶意脚本(例如想偷数据、弹窗、跳转),在沙箱里也:
拿不到宿主页面 DOM / Cookie /localStorage;
无法联网外传;
无法嵌套弹窗或表单。
一句话:AI 可以随便写,但只能在自己的 "小黑屋" 里跑。
dsh-openmaic-main/
├── package.json # 包定义:入口、导出、依赖、工具/技能清单
├── dsh.plugin.json # dsh 插件清单(工具 + 技能列表)
├── cordis.patch.yml # 构建时把插件插入 dsh 配置层的补丁
├── tsdown.config.ts # 双端打包配置(Node 端 + 浏览器端)
├── tsconfig.json # Node 端 TypeScript 配置
├── tsconfig.client.json # 浏览器端 TypeScript 配置
├── README.md # 英文简介
├── LICENSE # MIT 协议
│
├── src/ # ★ 源码(TypeScript)
│ ├── index.ts # 插件入口:注册 4 工具 + 4 技能 + 4 段系统提示 + 配置定义
│ ├── client.ts # openmaic_generate 的 API 客户端(提交作业 + 轮询)
│ ├── tool.ts # openmaic_render 工具定义
│ ├── widget.ts # openmaic_widget 工具定义
│ ├── slide.ts # openmaic_slide 工具定义(画布固定 1280×720)
│ ├── skill.ts # 4 个 bundled 技能的提供者(从 assets/ 读正文)
│ ├── fragment.ts # ★ 共享契约:片段校验 + meta 类型(纯函数)
│ ├── slide-meta.ts # ★ 共享契约:幻灯片 meta
│ ├── widget-meta.ts # ★ 共享契约:组件 meta + 流式解析
│ └── client/ # ★ 浏览器端(React 组件)
│ ├── index.tsx # 注册 toolview(卡片/组件/幻灯片)+ 流式预览 dock
│ ├── OpenmaicCard.tsx # 教学卡片渲染组件
│ ├── WidgetCard.tsx # 互动组件渲染组件(含展开大窗)
│ ├── SlideCard.tsx # 幻灯片渲染组件(用 @openmaic/renderer)
│ ├── StreamingWidgetPreview.tsx # 写代码时的实时预览
│ ├── shell.ts # 沙箱 iframe 文档 + CSP 组装
│ ├── frame-css.ts # 卡片内置样式表(card/btn/viz-* 类)
│ ├── theme.ts # 宿主主题 → 卡片主题桥接
│ └── shiki-stub.ts # 代码高亮库 shiki 的桩(浏览器里不可用,降级纯文本)
│
├── assets/ # ★ 技能正文与模板(打包进插件)
│ ├── openmaic-render.md # render 技能正文
│ ├── openmaic-widget.md # widget 技能正文
│ ├── openmaic-slide.md # slide 技能正文
│ ├── openmaic-teach.md # teach 技能正文
│ ├── slide-template/ # 幻灯片生成契约(system.md + user.md)
│ └── widget-templates/ # 组件模板(simulation / game / code)
│
├── lib/ # 编译产物(随插件分发,git 安装无需构建)
│ ├── index.js # Node 端产物
│ ├── client.js # 浏览器端产物(单文件经典脚本)
│ └── index.d.ts # 类型声明
│
├── scripts/
│ ├── build.sh # 构建脚本(链接 dsh 依赖 + tsdown 打包 + 产物校验)
│ └── test.sh # 测试脚本(链接依赖 + 跑 vitest)
│
└── tests/ # ★ 测试
├── plugin.spec.ts # 集成测试:真实 Cordis 组合下注册/系统提示/技能
├── client.spec.ts # openmaic_generate 客户端测试
├── fragment.spec.ts # 片段契约测试
├── widget.spec.ts # 组件 meta + 流式解析测试
└── slide.spec.ts # 幻灯片 meta 测试
src/index.ts** 是总开关**:apply() 函数里 ctx.effect(...) 依次注册了工具、技能、系统提示段落。看懂了它就看懂了插件贡献了什么。
"meta 传递" 机制:Node 端把内容写进 tool/result 的 meta,浏览器端从 meta 取内容渲染。内容不通过 "文本流" 回传给模型(省 token),也保证回放一致性。
共享契约模块是纯函数:fragment.ts / slide-meta.ts / widget-meta.ts 无 I/O、无 DOM、不引入宿主包的值,所以 Node 端、浏览器端、vitest 都能直接加载 —— 这是构建约束(浏览器 bundle 不能 require 宿主模块)逼出来的优雅设计。
需要有一个 DeepSeek Harness 的源码检出(checkout),构建 / 测试脚本会从中拿依赖。
脚本自动定位方式:从 PATH 上的 dsh 命令反推出 checkout;也可用环境变量 DSH_CHECKOUT 手动指定。
./scripts/build.sh # 或 npm run build
脚本做的事:
定位 harness checkout;
把 dsh 的宿主依赖软链接进本项目的 node_modules(保证用同一份 vendored 包编译);
用 tsdown 分别打包:
Node 端:src/index.ts → lib/index.js + .d.ts(ESM,schemastery/cordis 保持外部);
浏览器端:src/client/index.tsx → lib/client.js(单个 CJS 文件,通过 window.__ModuleLoader__.load(...) 包装,平台模块保持外部,其余全部内联);
lib/client.js 里 require() 的模块全在白名单内、没有遗留动态 import()、没有拆分成多个 chunk—— 任何一条不满足就报错退出(因为浏览器加载器只能加载一个经典脚本)。npm run typecheck # tsc -p tsconfig.json && tsc -p tsconfig.client.json
./scripts/test.sh # 或 npm test(链接依赖后跑 vitest)
测试覆盖:
client.spec.ts:课堂生成客户端的提交、轮询、失败、超时、Cookie、URL 兜底;
fragment.spec.ts / widget.spec.ts / slide.spec.ts:三个契约的校验与 meta 收窄;
plugin.spec.ts:用真实的 Cordis 组合(SessionStore + SystemPrompt + SkillService + ToolRegistry + 本插件)验证工具注册、系统提示注入、技能目录可用。
| 报错 | 含义 |
|---|---|
cannot locate the harness checkout |
没找到 dsh 源码;设置 DSH_CHECKOUT 或把 dsh 放进 PATH |
lib/client.js requires modules the loader module table cannot answer |
浏览器端引入了不该引入的 Node 端模块(比如 import 了宿主包的值);把共享逻辑挪进纯模块 |
kept dynamic imports the browser cannot resolve |
浏览器产物里残留动态 import;要内联或用本地 stub 替换 |
browser bundle split into chunks |
打包被拆成多文件;浏览器加载器无法拉取,需要内联 |
本项目处于 developer preview 阶段,dsh 本身也在快速迭代,会有破坏性变更。
组件类型目前只接了 3 种:simulation、game、code。
openmaic_render / openmaic_widget / openmaic_slide 三个渲染工具不做服务端生成,只渲染 AI 按契约手写的内容(依托 @openmaic/dsl、@openmaic/generation、@openmaic/renderer SDK)。
代码高亮(shiki)在浏览器端不可用,代码块以纯文本渲染(框架、行号、内容都在,只是没有语法配色)—— 这是刻意取舍,见 shiki-stub.ts。
接线剩余组件类型:diagram(图表)、visualization3d(3D 可视化)、procedural-skill(程序化技能);
动作回环到模型:让 "教学代理" 能对组件做 highlight(高亮)/ annotate(标注)/ reveal(揭示)等驱动动作(组件里已预留好 postMessage 监听器)。
Q1:装上插件后为什么 AI 会 "突然" 开始做卡片 / 幻灯片?
A:这是正常的。插件给 dsh 注入了 4 段系统提示,教会模型 "什么场景该用哪个工具";模型判断可视化更有帮助时就会自动调用。
Q2:openmaic_generate** 生成课堂要等多久?**
A:异步作业 + 轮询,默认最长等 10 分钟(maxWaitMs),轮询间隔默认 5 秒。官方建议把 pollIntervalMs 调到 60000,更省资源。
Q3:AI 生成的 HTML 安全吗?会不会偷我的数据?
A:渲染在 <iframe sandbox="allow-scripts"> + 强 CSP 的沙箱里,opaque origin、不能联网、不能访问宿主页面,详见第七章。
Q4:为什么我的 openmaic_render 调用报 "document-skeleton" 错误?
A:你把 <!doctype> / <html> / <head> / <body> 写进 fragment 了。卡片自己会提供文档骨架,你只需要写正文片段(标签 + 样式 + 可选脚本)。
Q5:组件里的代码为什么没有语法高亮?
A:shiki 在浏览器端插件环境里无法打包,项目用一个 stub 让它降级为纯文本渲染(有代码框、行号、内容,只是没有配色)。这是已知取舍。
Q6:我想对接自己部署的 OpenMAIC,怎么改?
A:把配置 baseUrl 指向你的实例(如 http://localhost:3000)即可,其余流程不变。
Q7:改完源码怎么让改动生效?
A:运行 ./scripts/build.sh 重新打包到 lib/,然后重启 dsh web。注意需要能定位到 harness checkout。
Q8:这个插件能离线使用吗?
A:部分可以。openmaic_render / openmaic_widget / openmaic_slide 全部本地渲染、无需联网(沙箱本身也禁止联网);只有 openmaic_generate 需要访问 open.maic.chat 服务。
本说明书基于项目源码(v0.4.0)整理,涵盖全部 4 个工具、4 个技能、双端架构、安全机制、构建与测试流程。如有疑问,可对照 README.md 与 src/ 源码进一步阅读。