# MEMORY.md - 长期记忆 这个文件用于记录重要的长期知识和经验教训。 --- ## DingTalk媒体发送成功经验 **日期**: 2026-03-05 **重要性**: ⭐⭐⭐⭐⭐ ### 问题背景 尝试通过DingTalk发送文件时遇到多次失败,反复尝试了多种方法: - 使用message工具 - 失败("Failed to upload media") - 直接调用robot/send API - 失败("token is not exist" / "缺少参数 access_token") - 尝试不同的API端点和消息格式 - 大部分失败 ### 解决方案(成功方式) #### Token获取 ```javascript // 关键:使用GET + URL参数(非params) const tokenUrl = `https://oapi.dingtalk.com/gettoken?appkey=${APP_KEY}&appsecret=${APP_SECRET}`; const response = await axios.get(tokenUrl); const accessToken = response.data.access_token; ``` **重要**:不要使用`axios.get(url, {params: {...}})`,必须在URL中直接拼接参数 #### 文件上传 ```javascript 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'); const upload = await axios.post(uploadUrl, form, {headers: form.getHeaders()}); const media_id = upload.data.media_id; ``` #### 消息发送(关键成功点) ```javascript const url = "https://api.dingtalk.com/v1.0/robot/groupMessages/send"; const headers = { "x-acs-dingtalk-access-token": accessToken, // ← 关键:在Header中 "Content-Type": "application/json" }; const body = { robotCode: ROBOT_CODE, openConversationId: OPEN_CONVERSATION_ID, msgKey: "sampleFile", // ← 文件用sampleFile,图片用sampleMarkdown msgParam: JSON.stringify({ // ← 关键:必须是字符串! mediaId: media_id, fileName: fileName }) }; const result = await axios.post(url, body, { headers }); ``` ### 关键msgKey对应关系 | 媒体类型 | msgKey | 测试状态 | |---------|--------|---------| | 文件 | `sampleFile` | ✅ 验证成功 | | 图片 | `sampleMarkdown` | ✅ 验证成功 | | 视频 | `sampleVideo` | 待测试 | ### 失败原因总结 1. **使用旧的robot/send API** - 返回 "token is not exist" - 使用v1.0 API后解决 2. **msgParam使用对象而非字符串** - 返回 "MissingmsgParam" - 必须使用`JSON.stringify()` 3. **access_token放在错误位置** - 在URL中会失败 - 必须在Header中:`x-acs-dingtalk-access-token` ### 验证的端点差异 | API端点 | 状态 | 说明 | |---------|------|------| | `https://oapi.dingtalk.com/gettoken` | ✅ 可用 | 必须用URL参数 | | `https://oapi.dingtalk.com/media/upload` | ✅ 可用 | 支持文件上传 | | `https://api.dingtalk.com/v1.0/robot/groupMessages/send` | ✅ 可用 | 成功发送消息 | | `https://oapi.dingtalk.com/robot/send` | ❌ 失败 | 返回token错误 | ### 配置信息 ``` AppKey: ding4ursdp0l2giat4bj AppSecret: J0gBicjKiIHoKla7WfKKhRs1Tv8L6Xd5UhW3EVQByF16G7Vn7UUcRhP6u-PBCQNo RobotCode: ding4ursdp0l2giat4bj OpenConversationId: cidcjYshXVtKck5LfOO9AqOJg== ``` ### 成功案例 **2026-03-05 18:44** - 项目:database_analysis_summary.txt - 文件大小:3,155 bytes - media_id: @lAjPM2GaR32g2U3OC2pNq84Clg_0 - msgKey: sampleFile - API: /v1.0/robot/groupMessages/send - ProcessQueryKey: lXs/uLRd0YxJVk1x0VyTLfSdY2YKCE1yrGn2vGlQ+GM= - 状态:成功发送到钉钉群聊 ### 经验教训 1. **不要在OpenClaw环境中直接调用原始钉钉API** - OpenClaw插件会拦截请求 - 认证可能不匹配 2. **msgKey是关键** - 文件 → sampleFile - 图片 → sampleMarkdown - 视频 → sampleVideo 3. **msgParam必须是JSON字符串** - 这是容易出错的地方 - 必须用`JSON.stringify()`包裹 4. **使用正确的API版本** - v1.0 API是正确选择 - 旧版API不再有效 --- ## Python环境问题 **日期**: 2026-03-05 **重要性**: ⭐⭐⭐ **问题**: PowerShell直接调用Python时遇到路径和编码问题 **解决方案**: 1. 设置PATH: `$env:PATH = "F:\pyenv\pyenv-win\pyenv-win\pyenv-win\versions\3.14.2;$env:PATH"` 2. 使用UTF-8编码: `sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')` --- ## Git配置 **日期**: 2026-03-05 **重要性**: ⭐⭐⭐ **Git服务器**: git.alicorns.co.jp (Gitea) **用户**: aitest **密码**: Aiitest123456 **主要仓库**: - `aitest/office-file-handler.git` - `aitest/dingtalk-media-sender.git` - `aitest/workspace.git` --- ## 记录准则 1. 只记录重要且会重复用到的信息 2. 包括成功和失败的经验 3. 提供可执行的代码示例 4. 标注日期和重要性