Files
workspace/TOOLS.md

4.4 KiB
Raw Permalink Blame History

TOOLS.md - Local Notes

Skills define how tools work. This file is for your specifics — the stuff that's unique to your setup.

What Goes Here

Things like:

  • Camera names and locations
  • SSH hosts and aliases
  • Preferred voices for TTS
  • Speaker/room names
  • Device nicknames
  • Anything environment-specific

Examples

### Cameras

- living-room → Main area, 180° wide angle
- front-door → Entrance, motion-triggered

### SSH

- home-server → 192.168.1.100, user: admin

### TTS

- Preferred voice: "Nova" (warm, slightly British)
- Default speaker: Kitchen HomePod

Why Separate?

Skills are shared. Your setup is yours. Keeping them apart means you can update skills without losing your notes, and share skills without leaking your infrastructure.


DingTalk Configuration

  • AppKey: ding4ursdp0l2giat4bj
  • AppSecret: J0gBicjKiIHoKla7WfKKhRs1Tv8L6Xd5UhW3EVQByF16G7Vn7UUcRhP6u-PBCQNo
  • robotCode: ding4ursdp0l2giat4bj
  • OpenConversationId: cidcjYshXVtKck5LfOO9AqOJg==

DingTalk成功发送的关键配置

Token获取必须使用GET + URL参数

// ✓ 正确方式
const tokenUrl = `https://oapi.dingtalk.com/gettoken?appkey=${APP_KEY}&appsecret=${APP_SECRET}`;
const token = await axios.get(tokenUrl).data.access_token;

// ✗ 错误方式(会失败)
const tokenUrl = "https://oapi.dingtalk.com/gettoken";
const token = await axios.get(tokenUrl, {
  params: {appkey: APP_KEY, appsecret: APP_SECRET}
}).data.access_token;

v1.0 API发送消息成功方式

// API端点
const url = "https://api.dingtalk.com/v1.0/robot/groupMessages/send";

// Headers关键包含access_token
const headers = {
  "x-acs-dingtalk-access-token": accessToken,
  "Content-Type": "application/json"
};

// Body格式
const body = {
  robotCode: ROBOT_CODE,
  openConversationId: OPEN_CONVERSATION_ID,
  msgKey: "sampleFile",  // 或 "sampleMarkdown"
  msgParam: JSON.stringify({  // ← 必须是字符串!
    mediaId: media_id,
    fileName: "file.txt"
  })
};

await axios.post(url, body, { headers });

关键msgKey对应关系

媒体类型 msgKey 说明
文件 sampleFile 发送.txt, .docx, .pdf等文件
图片 sampleMarkdown 使用Markdown格式嵌入图片
视频 sampleVideo 发送.mp4等视频文件待测试

重要注意事项

  1. msgParam必须是字符串

    // ✓ 正确
    msgParam: JSON.stringify({mediaId: "@xxx", fileName: "test.txt"})
    
    // ✗ 错误
    msgParam: {mediaId: "@xxx", fileName: "test.txt"}
    
  2. 直接调用API会失败于OpenClaw环境

    • OpenClaw的DingTalk插件会拦截所有API请求
    • 直接调用robot/send会返回"token is not exist"或"缺少参数 access_token"
    • 必须使用v1.0 API + Headers中的access_token
  3. 文件上传API

    // 上传GET方式获取token已经验证有效
    const uploadUrl = `https://oapi.dingtalk.com/media/upload?access_token=${accessToken}`;
    const form = new FormData();
    form.append('media', fs.createReadStream(filePath));
    form.append('type', 'file');
    await axios.post(uploadUrl, form, {headers: form.getHeaders()});
    

OpenClaw Runtime 环境说明

  • 系统 Node 由 nvm 管理。
  • OpenClaw 与 Skill 执行使用独立 NodeF:/openclaw-runtime,不受 nvm 切换影响。
  • 系统 Python 由 pyenv-win 管理。
  • OpenClaw 也使用独立 Python 运行环境,不受系统 pyenv 切换影响。

成功案例记录

2026-03-05 18:44 - 成功发送database_analysis_summary.txt

  • 文件: database_analysis_summary.txt (3,155 bytes)
  • media_id: @lAjPM2GaR32g2U3OC2pNq84Clg_0
  • msgKey: sampleFile
  • API: /v1.0/robot/groupMessages/send
  • ProcessQueryKey: lXs/uLRd0YxJVk1x0VyTLfSdY2YKCE1yrGn2vGlQ+GM=

默认发图稳定流程(柏方确认)

当用户说“发图”时,默认按以下顺序执行:

  1. GET https://oapi.dingtalk.com/gettoken?appkey=...&appsecret=... 获取 token
  2. POST https://oapi.dingtalk.com/media/upload?access_token=... 上传图片,获取 media_id
  3. POST https://api.dingtalk.com/v1.0/robot/groupMessages/send 发送消息
    • Header: x-acs-dingtalk-access-token: <token>
    • msgKey = sampleMarkdown
    • msgParam 必须是 JSON 字符串(内嵌图片)

Add whatever helps you do your job. This is your cheat sheet.