@scholai/openclaw-scholai
v0.1.20
Published
OpenClaw scholai courseware plugin (MVP: article via lobster pipeline)
Readme
@scholai/openclaw-scholai
OpenClaw plugin providing scholai courseware generation pipelines as a skill.
后台异步执行的课件生成管线:用户发命令 → 主会话立即返回 → 后台 subagent 通过 Lobster 顺序跑 Python CLI atom 链 → 完成后通过 OpenClaw announce 自动回传消息。MVP 已支持 article / mindmap / exercise / video 四个 kind,输入源可以是 URL,也可以是飞书视频消息(回复一条视频 + 命令;其他媒体类型如 mp3 / pdf 暂未作为输入支持)。
Skill
| 命令 | 状态 | 说明 | publish payload |
|------|------|------|-----------------|
| /scholai article <url> 或 回复视频 + /scholai article | ✅ MVP | 生成 HTML 图文教材(含 LLM 生成的配图),发布到 Scholai 平台 | output/article.html |
| /scholai mindmap <url> 或 回复视频 + /scholai mindmap | ✅ MVP | 生成 markmap 思维导图(Markdown,scholai 后端 markmap 渲染) | output/mindmap.md |
| /scholai exercise <url> 或 回复视频 + /scholai exercise | ✅ MVP | 生成混合题型习题集(Markdown,后端 MARKDOWN_KINDS 白名单) | output/exercise.md |
| /scholai video <url> 或 回复视频 + /scholai video | ✅ MVP | 6-atom pipeline → ≤180s 短视频,自动推回原 IM 会话 | 无(MVP 跳过 OSS/publish;直接 lark-send) |
每个 kind 一份 lobster pipeline + 一份 references doc:
- article —
skills/scholai/pipelines/article.lobster+skills/scholai/references/article.md - mindmap —
skills/scholai/pipelines/mindmap.lobster+skills/scholai/references/mindmap.md - exercise —
skills/scholai/pipelines/exercise.lobster+skills/scholai/references/exercise.md - video —
skills/scholai/pipelines/video.lobster+skills/scholai/references/video.md
主入口(kind-agnostic 主会话流程、卡片协议、subagent 派发约定)见 skills/scholai/SKILL.md。新增 kind 直接照已有 kind 的形态加一份 lobster pipeline + references doc + SKILL.md 命令索引一行即可。
飞书裸媒体拦截钩子
插件注册了一个 before_dispatch 钩子,会静默吞掉飞书 channel 上的裸媒体消息(任何 <media:*> 包络:<media:video> / <media:audio> / <media:image> / <media:document> / <media:sticker> 等),让模型不会在用户的 /scholai 命令到达之前就自作主张地分析这条媒体。
"回复媒体 + /scholai <kind>" 的正常工作流不受影响 —— 那条后续消息携带的是普通文本,不是 <media:*> 包络。
每次 claim 会向 <state-dir>/logs/scholai-inbound.log 追加一行。state-dir 的解析顺序:$SCHOLAI_INBOUND_LOG_PATH(操作员显式指定)→ $OPENCLAW_STATE_DIR(openclaw 注入时使用)→ $HOME/.openclaw(普通安装)→ os.tmpdir()(最后兜底)。
[openclaw-scholai inbound_claim] claimed feishu bare-media (kind=document, file=audio.mp3, msgId=om_xxx, session=..., sender=...)诊断用 env(追加到 openclaw service env 文件,例如 macOS 下的 <state-dir>/service-env/ai.openclaw.gateway.env,然后 launchctl kickstart -k gui/$(id -u)/ai.openclaw.gateway 重启服务):
| Env | 默认值 | 用途 |
|------|--------|------|
| SCHOLAI_DEBUG_INBOUND | 未设置 | 设为 1 时,每条入站事件都会以 [hook=before_dispatch] tag 输出完整 payload。日志量较大,仅排查时打开。 |
| SCHOLAI_INBOUND_LOG_PATH | 见上面的解析顺序 | 覆盖 fs append 的目标路径。 |
实现见 src/hooks/inbound-media-claim.ts。注册到的是 before_dispatch 而不是 inbound_claim —— 实测在 OpenClaw v2026.5.x 上,inbound_claim 钩子对飞书入站事件不触发。
执行架构
SKILL.md (kind-agnostic)
│ user 输入:
│ (A) /scholai <kind> <url> — URL 模式
│ (B) 回复一条视频消息 + /scholai <kind> — 视频模式(通过 parent_msg_id 回溯)
▼
MainAgent
│ 1. 解析输入源(URL / 飞书 file_key),写 source.json
│ 2. 生成 run_id (UUID v4)
│ 3. 创建 cardkit 进度卡片 → 推到 requester channel
│ 4. sessions_spawn (context: isolated, runTimeoutSeconds: per-kind)
│ 5. 立即回 "📋 进度卡片已发送"
▼
Subagent (后台一次性会话,主会话不阻塞)
│ 调 lobster agent tool
│ pipeline: skills/scholai/pipelines/<kind>.lobster
│ argsJson: {"run_id":"...","source_json":"...","card_id":"...","plugin_dir":"..."}
▼
Lobster runtime — 顺序跑 atoms,每个 atom 后接 notify_<id> 翻卡片行
│
│ article.lobster (5 业务步, ~5–15 分钟):
│ setup → vfd → iod → pd → txd_gen → txd_imagegen
│ → txd_render_html → publish
│
│ mindmap.lobster (3 业务步, ~1–3 分钟):
│ setup → vfd → iod → mmd_gen → mmd_render_html → publish
│
│ exercise.lobster (3 业务步, ~1–3 分钟):
│ setup → vfd → iod → esd_gen → publish
│
│ video.lobster (6 业务步, ≤180s):
│ setup → vfd-url → ssd-gen → ssd-imagegen → tts-gen
│ → video-compose → lark-send
▼
Subagent → PATCH 卡片 footer 为 🎉 + URL 或 ❌ + error → 输出 NO_REPLY
│
▼ (footer PATCH 失败 OR card_id 为空时回退) OpenClaw 自动 announce 到 requester channel各 kind 的具体超时、atom 失败映射、subagent task 模板:
- skills/scholai/references/article.md
- skills/scholai/references/mindmap.md
- skills/scholai/references/exercise.md
- skills/scholai/references/video.md
Installation
openclaw plugin install @scholai/openclaw-scholaiSkill 声明了 metadata.openclaw.install: [kind: uv, package: scholai-cli],
openclaw 在首次调用 skill 时会自动通过 uv 安装 Python atom CLI(scholai)。
Prerequisites
- Node ≥ 22(plugin 本身)
- openclaw(自带
lobsteragent tool plugin,本 skill 必需) uv≥ 0.7 on PATH — 用于 Python atom 安装,见 https://docs.astral.sh/uv/lobsterCLI on PATH —@openclaw/lobster插件需要 spawn 这个 binary。openclaw 当前不会自动安装它(详见 [openclaw#TBD]),手动一次:
装完npm i -g @clawdbot/lobster # 或 npm install -g @clawdbot/lobsterwhich lobster应能找到。
Configuration
用户通过 @scholai/openclaw-scholai-tools install(separate package, npm run onboard 走的就是它)配置以下凭据 / 模型:
| 变量 | 必需 | 用途 |
|------|------|------|
| LLM_TEXT_API_KEY | ✅ | 文本模型 API key |
| LLM_TEXT_BASE_URL | ✅ | 文本模型 OpenAI-兼容网关 base URL |
| LLM_TEXT_MODEL | ✅ | 文本模型 ID(用于 iod / pd / txd-gen / mmd-gen) |
| LLM_IMAGE_API_KEY | ✅ | 图像模型 API key |
| LLM_IMAGE_BASE_URL | ✅ | 图像模型 OpenAI-兼容网关 base URL |
| LLM_IMAGE_MODEL | ✅ | 图像模型 ID(用于 article kind 的 txd-imagegen) |
| SCHOLAI_API_KEY | ✅ | publish 到 scholai 后端的鉴权 token |
| SCHOLAI_API_URL | ✅ | scholai 平台 base URL,publish 拼接 /api/document |
| VOLC_ASR_API_KEY | ✅ | 火山 ASR(语音识别)凭证,飞书视频 / 音频输入用 |
| VOLC_VISION_API_KEY | ✅ | 火山 VISION(视觉理解)凭证,飞书视频 / PPT 输入用 |
| TENCENTCLOUD_SECRET_ID | ✅ | 腾讯云 COS 凭证 ID,PPT 输入上传中转用 |
| TENCENTCLOUD_SECRET_KEY | ✅ | 腾讯云 COS 凭证 Key |
| TENCENTCLOUD_COS_BUCKET | ✅ | 腾讯云 COS bucket 名 |
| TENCENTCLOUD_COS_REGION | ✅ | 腾讯云 COS 区域(如 ap-shanghai) |
Atom 通过 OpenAI 兼容 SDK 调 LLM(不是 Gemini),所以接火山 / DeepSeek / OpenAI 自己 / 任何 OpenAI-compatible 网关都行,只要给对应的 base URL + API key + 模型 ID 即可。
Keys 通过 openclaw 的 skills.entries.<skill>.env 机制注入到 skill 运行时。
Development
npm run build --workspace=@scholai/openclaw-scholai
npm test --workspace=@scholai/openclaw-scholai
npm run typecheck --workspace=@scholai/openclaw-scholai