ReMe/skills/dingtalk-message/README.md
jinliyl 46adb5ae1e
Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Tests ReMe / Unit Tests - py3.11 (push) Has been cancelled
Tests ReMe / Unit Tests - py3.12 (push) Has been cancelled
Tests ReMe / Unit Tests - py3.13 (push) Has been cancelled
Windows Smoke / CLI smoke - py3.11 (push) Has been cancelled
feat: add daily paper cookbook and DingTalk agent integration (#385)
* feat(daily-paper): add daily paper cookbook workflow with schema and tests

- Introduce daily paper schema types (DailyBriefOutput, PaperInfo, PaperNoteOutput, etc.)
- Create daily paper cookbook module with analyze, collect, digest, rank, and select steps
- Add cookbook entry point and integrate into main steps module
- Replace job config export with daily brief output in schema exports
- Add comprehensive unit tests covering pipeline, filtering, and output generation
- Update dependencies including openai-codex and pypdf packages
- Configure standalone daily paper cron job with proper scheduling and routing

* test(daily_paper): update tests to use Claude Code wrapper exclusively

- Add test to verify web search is disallowed by default in Claude Code
- Update imports to include DailyBriefOutput, PaperNoteOutput, and PaperSelection schemas
- Change test name from standalone_config_has_backend_split to reflect Claude Code only usage
- Remove default agent wrapper and configure all steps to use Claude Code wrapper
- Rename select_wrapper to cc_wrapper for clarity and consistency
- Remove duplicate Claude Code wrapper initialization
- Update test assertions to verify output schema usage matches expected sequence
- Remove unused as_llm component from standalone configuration test

* refactor(agent-wrapper): simplify skill resolution logic across all wrappers

- Replace duplicate skill resolution code with centralized _resolve_project_skills method
- Add project_path property with configurable relative path resolution
- Introduce proper validation for skill names and directory existence
- Change Codex wrapper to use project_path instead of workspace_path for skills
- Add SKILL.md requirement validation for project skills
- Remove redundant skill processing logic from individual wrappers

* feat(daily_paper): add daily paper workflow with PDF analysis and brief generation

- Implement shared state management and file helpers for daily-paper steps
- Add PDF download and text extraction capabilities with arXiv integration
- Create paper collection step with Hugging Face weekly/monthly rankings
- Build ranking system using reciprocal-rank fusion with memory keyword scoring
- Add Claude Code integration for paper analysis and detailed note generation
- Implement digest step to create final five-minute brief from detailed notes
- Add configuration for standalone daily cookbook application with cron scheduling
- Create typed schema for paper information, selection, and output formats
- Add atomic file writing with temporary file safety mechanisms
- Implement exclusion logic for previously recommended papers and daily filters

* feat(daily_paper): add DingTalk notification integration and enhance logging

- Integrate DingTalk markdown send step to notify groups about daily paper briefs
- Add comprehensive logging throughout daily paper workflow including start/finish events
- Update daily paper analysis prompt to include code repository context requirement
- Configure DingTalk notification in daily_cookbook.yaml with app credentials
- Add dingtalk-stream dependency for proactive message API integration
- Enhance daily paper README with DingTalk notification section and updated flow chart
- Implement detailed logging for each step including paper processing and agent calls
- Add test coverage for DingTalk markdown sending functionality and configuration
- Update pre-commit config to exclude skills directory from checks
- Add .claude/skills to gitignore for local development environment

* refactor(dingtalk): move dingtalk_stream import to local scope and improve code safety

- Moved global dingtalk_stream import to local scope in send.py to avoid eager loading
- Added dynamic import with error handling for optional dependency cases
- Updated test suite to verify lazy loading behavior works correctly
- Fixed markdown title generation by using safe variable naming in wait.py
- Enhanced test coverage for arxiv PDF download caching functionality
- Updated application context initialization with proper resource directory configuration
- Modified paper metadata to include source PDF path reference in output files

* refactor(daily_paper): remove manifest system and store selection metadata in digest files

- Remove JSON manifest creation and storage functionality
- Store selection data directly in digest file frontmatter instead of separate manifest files
- Add load_saved_selection method to rebuild selection from digest and paper-note metadata
- Update README documentation to reflect new cookbook workflow architecture
- Modify test cases to verify selection metadata in digest files instead of manifest JSON
- Remove unused json import from multiple daily paper modules
- Integrate PaperSelection schema for proper data validation in stored metadata

* docs(daily_paper): add bilingual cookbook guides
2026-07-22 19:17:01 +08:00

985 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 钉钉消息发送技能 (dingtalk-message)
钉钉消息发送 CLI 工具,支持**企业内部机器人**和 **Webhook 自定义机器人**两种接入方式,支持文本、Markdown、链接、ActionCard、FeedCard、文件等多种消息类型。
> 官方文档:https://open.dingtalk.com/document/development/development-robot-overview
## 目录
- [API 接口文档](#api-接口文档)
- [企业内部机器人](#一企业内部机器人-api)
- [批量发送单聊消息](#1-批量发送人与机器人会话中机器人消息)
- [发送群聊消息](#2-发送群聊消息)
- [获取 Access Token](#3-获取-access-token)
- [上传媒体文件](#4-上传媒体文件)
- [Webhook 自定义机器人](#二webhook-自定义机器人-api)
- [Webhook 概述](#webhook-概述)
- [安全设置](#安全设置)
- [Webhook 消息类型](#webhook-消息类型)
- [CLI 使用指南](#cli-使用指南)
- [配置说明](#配置说明)
- [消息类型详解](#消息类型详解)
- [Markdown 语法限制](#钉钉-markdown-语法限制)
- [错误码参考](#错误码参考)
- [注意事项与限制](#注意事项与限制)
---
## API 接口文档
### 一、企业内部机器人 API
### 1. 批量发送人与机器人会话中机器人消息
> 官方文档:https://open.dingtalk.com/document/development/chatbots-send-one-on-one-chat-messages-in-batches
#### 接口概述
调用本接口批量发送人与机器人会话(即人与机器人的单聊)中的机器人消息。通过该接口,企业内部应用的机器人可以向多个用户同时发送单聊消息。
#### 请求方式
- **HTTP 方法**:`POST`
- **URL**:`https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend`
#### 请求头
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `x-acs-dingtalk-access-token` | String | 是 | 调用服务端接口的授权凭证(access_token) |
| `Content-Type` | String | 是 | 固定值:`application/json` |
#### 请求体参数(Body)
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `robotCode` | String | 是 | 机器人的编码(robotCode),可在钉钉开发者后台的机器人管理页面获取 |
| `userIds` | List\<String\> | 是 | 接收消息的用户 userId 列表,最多支持 **100** 个 |
| `msgKey` | String | 是 | 消息模板 Key,用于指定消息类型,见下方[消息类型 msgKey 映射表](#消息类型-msgkey-映射表) |
| `msgParam` | String | 是 | 消息模板参数,JSON 字符串格式,内容结构取决于 `msgKey` 的类型 |
#### 消息类型 msgKey 映射表
| 消息类型 | msgKey 值 | 说明 |
|----------|-----------|------|
| 文本消息 | `sampleText` | 纯文本消息,支持 @用户 |
| 图片消息 | `sampleImage` | 需先上传获取 media_id |
| 语音消息 | `sampleVoice` | 需先上传获取 media_id |
| 文件消息 | `sampleFile` | 需先上传获取 media_id |
| 链接消息 | `sampleLink` | 带缩略图的链接卡片 |
| Markdown 消息 | `sampleMarkdown` | 支持有限 Markdown 语法 |
| ActionCard(单按钮) | `sampleActionCard` | 单按钮交互卡片 |
| ActionCard(多按钮) | `sampleMultiActionCard` | 多按钮交互卡片 |
#### 各消息类型 msgParam 结构
**文本消息 (`sampleText`)**
```json
{
"content": "消息内容",
"atUserIds": ["userId1", "userId2"] // 可选,@指定用户
}
```
**Markdown 消息 (`sampleMarkdown`)**
```json
{
"title": "消息标题",
"text": "#### 标题\n> 引用内容\n正文"
}
```
**链接消息 (`sampleLink`)**
```json
{
"title": "链接标题",
"text": "链接描述",
"messageUrl": "https://example.com",
"picUrl": "https://example.com/image.png" // 可选,缩略图
}
```
**图片消息 (`sampleImage`)**
```json
{
"mediaId": "@lADPxxxxxxxx",
"caption": "图片描述" // 可选
}
```
**文件消息 (`sampleFile`)**
```json
{
"mediaId": "@lADPxxxxxxxx",
"fileName": "报告.pdf",
"fileSize": "1024", // 可选,单位:字节
"fileType": "pdf" // 可选
}
```
**语音消息 (`sampleVoice`)**
```json
{
"mediaId": "@lADPxxxxxxxx",
"duration": "10", // 语音时长,单位:秒
"fileSize": "2048" // 可选,单位:字节
}
```
**ActionCard 单按钮 (`sampleActionCard`)**
```json
{
"title": "卡片标题",
"markdown": "#### 内容标题\n正文",
"singleTitle": "查看详情",
"singleUrl": "https://example.com"
}
```
**ActionCard 多按钮 (`sampleMultiActionCard`)**
```json
{
"title": "卡片标题",
"markdown": "#### 内容标题\n正文",
"btnOrientation": "0", // "0"=竖排,"1"=横排
"btns": [
{"title": "同意", "url": "https://example.com/approve"},
{"title": "拒绝", "url": "https://example.com/reject"}
]
}
```
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| `processQueryKey` | String | 消息发送任务的查询 Key,可用于查询发送结果 |
**成功响应示例:**
```json
{
"processQueryKey": "msgTaskId_xxx"
}
```
**错误响应示例:**
```json
{
"code": "InvalidParameter.RobotCode",
"message": "robotCode is invalid",
"requestid": "xxxx-xxxx-xxxx"
}
```
#### 请求示例(cURL)
```bash
curl -X POST 'https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend' \
-H 'x-acs-dingtalk-access-token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"robotCode": "dingxxxxxxxx",
"userIds": ["user001", "user002"],
"msgKey": "sampleText",
"msgParam": "{\"content\": \"Hello, 这是一条测试消息!\"}"
}'
```
#### 请求示例(Python)
```python
import requests
import json
url = "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend"
headers = {
"x-acs-dingtalk-access-token": "YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
}
payload = {
"robotCode": "dingxxxxxxxx",
"userIds": ["user001", "user002"],
"msgKey": "sampleText",
"msgParam": json.dumps({"content": "Hello, 这是一条测试消息!"})
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
---
### 2. 发送群聊消息
> 官方文档:https://open.dingtalk.com/document/orgapp/the-robot-sends-a-group-message
#### 接口概述
调用本接口向指定群聊发送机器人消息。机器人需要先加入群聊才能发送消息。
#### 请求方式
- **HTTP 方法**:`POST`
- **URL**:`https://api.dingtalk.com/v1.0/robot/groupMessages/send`
#### 请求头
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `x-acs-dingtalk-access-token` | String | 是 | access_token |
| `Content-Type` | String | 是 | 固定值:`application/json` |
#### 请求体参数(Body)
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `robotCode` | String | 是 | 机器人编码 |
| `openConversationId` | String | 是 | 群聊会话 ID |
| `msgKey` | String | 是 | 消息模板 Key |
| `msgParam` | String | 是 | 消息模板参数,JSON 字符串 |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| `processQueryKey` | String | 消息发送任务的查询 Key |
---
### 3. 获取 Access Token
> 官方文档:https://open.dingtalk.com/document/orgapp/obtain-the-access_token-of-an-internal-app
#### 请求方式
- **HTTP 方法**:`GET`
- **URL**:`https://oapi.dingtalk.com/gettoken`
#### 查询参数(Query)
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `appkey` | String | 是 | 应用的 AppKey |
| `appsecret` | String | 是 | 应用的 AppSecret |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| `errcode` | Number | 错误码,0 表示成功 |
| `errmsg` | String | 错误信息 |
| `access_token` | String | 访问凭证 |
| `expires_in` | Number | 有效期(秒),通常为 7200 |
#### 响应示例
```json
{
"errcode": 0,
"errmsg": "ok",
"access_token": "xxxxxx",
"expires_in": 7200
}
```
---
### 4. 上传媒体文件
> 用于发送图片、语音、文件类消息前的文件上传。
#### 请求方式
- **HTTP 方法**:`POST`
- **URL**:`https://oapi.dingtalk.com/media/upload`
#### 查询参数(Query)
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `access_token` | String | 是 | 访问凭证 |
#### 请求体参数(multipart/form-data)
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `type` | String | 是 | 文件类型:`image`/`voice`/`file` |
| `media` | File | 是 | 上传的文件 |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| `errcode` | Number | 错误码 |
| `errmsg` | String | 错误信息 |
| `media_id` | String | 媒体文件 ID,后续发送消息时使用 |
| `type` | String | 文件类型 |
| `created_at` | Number | 创建时间戳(毫秒) |
---
### 二、Webhook 自定义机器人 API
> 官方文档:https://open.dingtalk.com/document/orgapp/custom-bot-to-send-group-chat-messages
#### Webhook 概述
自定义机器人是一种可以直接添加到钉钉群聊的机器人,通过 Webhook URL 推送消息到群聊。与企业内部机器人不同,不需要创建应用、不需要 OAuth Token 流程,只需 POST JSON 到 Webhook URL 即可。
**适用场景:**
- 监控告警通知
- CI/CD 构建通知
- 定时数据报告推送
- 简单的群聊消息推送
**Webhook URL 格式:**
```
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX
```
#### 请求方式
- **HTTP 方法**:`POST`
- **Content-Type**:`application/json; charset=utf-8`
- **频率限制**:每个机器人每分钟最多发送 **20** 条消息
#### 安全设置
创建自定义机器人时,必须至少选择以下三种安全方式之一:
**方式一:自定义关键词**
- 最多设置 10 个关键词
- 消息内容必须包含至少一个关键词,否则被拒绝
**方式二:IP 地址白名单**
- 配置允许的 IP 地址或 CIDR 段
- 仅允许白名单内的 IP 发送消息
**方式三:加签(推荐)**
启用加签后,每次请求需要在 URL 中附加 `timestamp` 和 `sign` 参数。
**签名算法:**
```
timestamp = 当前毫秒时间戳
string_to_sign = timestamp + "\n" + secret
sign = URL_Encode(Base64(HMAC-SHA256(secret, string_to_sign)))
```
**签名后的 URL:**
```
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX&timestamp=1609459200000&sign=YYYY
```
> 时间戳与服务器时间差不能超过 1 小时,否则请求被拒绝。
> 脚本已内置加签逻辑,只需在配置文件中设置 `webhook_secret` 即可自动签名。
**Python 签名示例:**
```python
import time, hmac, hashlib, base64, urllib.parse
def generate_sign(secret: str):
timestamp = str(round(time.time() * 1000))
string_to_sign = f'{timestamp}\n{secret}'
hmac_code = hmac.new(
secret.encode('utf-8'),
string_to_sign.encode('utf-8'),
digestmod=hashlib.sha256
).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
return timestamp, sign
```
#### Webhook 消息类型
##### 文本消息 (text)
```json
{
"msgtype": "text",
"text": {
"content": "消息内容"
},
"at": {
"atMobiles": ["13800138000"],
"atUserIds": ["user123"],
"isAtAll": false
}
}
```
##### Markdown 消息 (markdown)
```json
{
"msgtype": "markdown",
"markdown": {
"title": "标题(通知栏显示)",
"text": "#### 标题\n> 引用内容\n正文"
},
"at": {
"atMobiles": ["13800138000"],
"isAtAll": false
}
}
```
##### 链接消息 (link)
> 不支持 @功能
```json
{
"msgtype": "link",
"link": {
"title": "链接标题",
"text": "链接描述",
"messageUrl": "https://example.com",
"picUrl": "https://example.com/image.png"
}
}
```
##### ActionCard 单按钮 (actionCard)
```json
{
"msgtype": "actionCard",
"actionCard": {
"title": "卡片标题",
"text": "#### 内容\n正文(支持 Markdown)",
"btnOrientation": "0",
"singleTitle": "阅读全文",
"singleURL": "https://example.com/"
}
}
```
##### ActionCard 多按钮 (actionCard)
```json
{
"msgtype": "actionCard",
"actionCard": {
"title": "卡片标题",
"text": "#### 内容\n正文",
"btnOrientation": "0",
"btns": [
{"title": "同意", "actionURL": "https://example.com/approve"},
{"title": "拒绝", "actionURL": "https://example.com/reject"}
]
}
}
```
> 注意:多按钮时使用 `btns` + `actionURL`,不要同时设置 `singleTitle`/`singleURL`
##### FeedCard 消息 (feedCard)
> 不支持 @功能
```json
{
"msgtype": "feedCard",
"feedCard": {
"links": [
{
"title": "链接标题1",
"messageURL": "https://example.com/1",
"picURL": "https://example.com/pic1.png"
},
{
"title": "链接标题2",
"messageURL": "https://example.com/2",
"picURL": "https://example.com/pic2.png"
}
]
}
}
```
#### Webhook 响应
**成功:**
```json
{
"errcode": 0,
"errmsg": "ok"
}
```
**错误示例:**
```json
{
"errcode": 310000,
"errmsg": "keywords not in content"
}
```
#### 请求示例(cURL)
```bash
curl -X POST 'https://oapi.dingtalk.com/robot/send?access_token=XXXXXX' \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{
"msgtype": "text",
"text": {
"content": "Hello, 这是一条 Webhook 测试消息!"
}
}'
```
#### Webhook 与企业内部机器人对比
| 维度 | Webhook 自定义机器人 | 企业内部机器人 |
|------|---------------------|---------------|
| **接入方式** | 群聊添加自定义机器人 | 钉钉开放平台创建应用 |
| **API 域名** | `oapi.dingtalk.com/robot/send` | `api.dingtalk.com/v1.0/robot/` |
| **认证方式** | URL 中的 access_token + 可选签名 | Header 中的 OAuth access_token |
| **配置项** | webhook_url, webhook_secret | app_key, app_secret, robot_code |
| **消息范围** | 仅所在群聊 | 任意用户/群聊 |
| **消息格式** | `msgtype` + 类型对象 | `msgKey` + `msgParam` (JSON 字符串) |
| **频率限制** | 20 条/分钟 | 20 次/秒 |
| **Token 管理** | 无需刷新(URL 固定) | Token 每 2 小时过期 |
---
## CLI 使用指南
### 安装依赖
```bash
pip install requests
```
### 命令行格式
```bash
# 企业内部机器人
python scripts/dingtalk.py <消息类型> [选项参数] "<消息内容>" --users <用户ID>
# Webhook 自定义机器人(命令以 webhook- 前缀开头)
python scripts/dingtalk.py webhook-<消息类型> [选项参数] "<消息内容>"
```
### 企业内部机器人命令
#### 发送文本消息
```bash
# 单聊
python scripts/dingtalk.py text "Hello, 这是一条测试消息!" --users user001,user002
# @指定用户
python scripts/dingtalk.py text "Hello, @user001" --users user001,user002 --at-users user001
# 群聊
python scripts/dingtalk.py text "大家好!" \
--mode group \
--conversation-id chatxxxxxxxxxxxxxxxx \
--at-mobiles 13800138000,13900139000
```
#### 发送 Markdown 消息
```bash
python scripts/dingtalk.py markdown \
--title "天气提醒" \
--users user001 \
"#### 杭州天气\n> 9度,西北风1级"
```
#### 发送链接消息
```bash
python scripts/dingtalk.py link \
--title "时代在进步" \
--url "https://www.dingtalk.com" \
--pic-url "https://example.com/image.png" \
--users user001 \
"点击查看详情"
```
#### 发送 ActionCard 消息
```bash
# 单按钮
python scripts/dingtalk.py action-card \
--title "审批通知" \
--single-title "查看详情" \
--url "https://www.dingtalk.com" \
--users user001 \
"#### 请假申请\n请审批"
# 多按钮
python scripts/dingtalk.py action-card \
--title "审批通知" \
--buttons "同意,https://approve.com/yes;拒绝,https://approve.com/no" \
--btn-orientation 0 \
--users user001 \
"#### 请假申请"
```
#### 发送文件
```bash
python scripts/dingtalk.py file \
--users user001,user002 \
--file /path/to/report.pdf \
--file-name "月度报告.pdf"
```
### Webhook 自定义机器人命令
> 所有 Webhook 命令以 `webhook-` 前缀开头。
> Webhook URL 可通过 `--webhook-url` 参数传入,或在配置文件中设置 `webhook_url`。
#### Webhook 发送文本消息
```bash
# 使用配置文件中的 webhook_url
python scripts/dingtalk.py webhook-text "Hello, 这是一条 Webhook 消息!"
# 通过参数指定 webhook URL
python scripts/dingtalk.py webhook-text \
--webhook-url "https://oapi.dingtalk.com/robot/send?access_token=xxx" \
"Hello, 测试消息"
# @指定手机号
python scripts/dingtalk.py webhook-text \
--at-mobiles 13800138000,13900139000 \
"通知内容 @13800138000"
# @所有人
python scripts/dingtalk.py webhook-text --at-all "全员通知"
```
#### Webhook 发送 Markdown 消息
```bash
python scripts/dingtalk.py webhook-markdown \
--title "天气提醒" \
"#### 杭州天气\n> 9度,西北风1级"
```
#### Webhook 发送链接消息
```bash
python scripts/dingtalk.py webhook-link \
--title "时代在进步" \
--url "https://www.dingtalk.com" \
--pic-url "https://example.com/image.png" \
"点击查看详情"
```
#### Webhook 发送 ActionCard 消息
```bash
# 单按钮
python scripts/dingtalk.py webhook-action-card \
--title "审批通知" \
--single-title "查看详情" \
--url "https://www.dingtalk.com" \
"#### 请假申请\n请审批"
# 多按钮
python scripts/dingtalk.py webhook-action-card \
--title "审批通知" \
--buttons "同意,https://approve.com/yes;拒绝,https://approve.com/no" \
--btn-orientation 0 \
"#### 请假申请"
```
#### Webhook 发送 FeedCard 消息
```bash
python scripts/dingtalk.py webhook-feed-card \
--links "新闻标题1,https://news1.com,https://img1.com/pic.png;新闻标题2,https://news2.com,https://img2.com/pic.png"
```
#### Webhook 使用加签
```bash
# 通过命令行参数
python scripts/dingtalk.py webhook-text \
--webhook-url "https://oapi.dingtalk.com/robot/send?access_token=xxx" \
--webhook-secret "SECxxxxxxxxxxxxxxxxxxxxxxxxxx" \
"带签名的消息"
# 或在配置文件中设置(推荐)
python scripts/dingtalk.py config --set webhook_secret=SECxxxxxxxxxxxxxxxxxxxxxxxxxx
```
### 查看帮助
```bash
python scripts/dingtalk.py --help
python scripts/dingtalk.py text --help
python scripts/dingtalk.py webhook-text --help
python scripts/dingtalk.py webhook-markdown --help
```
---
## 配置说明
### 配置文件
配置统一存储在系统配置目录,所有 AI agent 共享,无需重复配置:
| 平台 | 配置文件 | 状态文件 |
|------|---------|---------|
| macOS / Linux | `~/.config/dingtalk/config.json` | `~/.config/dingtalk/state.json` |
| Windows | `%APPDATA%\dingtalk\config.json` | `%APPDATA%\dingtalk\state.json` |
```json
{
"default_robot": "技术告警群",
"robots": [
{
"name": "技术告警群",
"type": "webhook",
"description": "发送技术告警到后端技术群",
"webhook_token": "YOUR_ACCESS_TOKEN",
"webhook_secret": ""
},
{
"name": "内部通知机器人",
"type": "app",
"description": "企业内部机器人,支持单聊和群聊",
"app_key": "YOUR_APP_KEY",
"app_secret": "YOUR_APP_SECRET",
"robot_code": "YOUR_ROBOT_CODE",
"agent_id": "YOUR_AGENT_ID"
}
]
}
```
### 参数获取说明
#### 企业内部机器人
| 参数 | 说明 | 获取方式 | 必填 |
|------|------|----------|------|
| `app_key` | 应用 AppKey | 钉钉开放平台 > 应用详情 > 凭证与基础信息 | 是 |
| `app_secret` | 应用 AppSecret | 钉钉开放平台 > 应用详情 > 凭证与基础信息 | 是 |
| `robot_code` | 机器人编号 | 钉钉开放平台 > 应用详情 > 机器人与消息推送 | 是 |
| `agent_id` | 应用 AgentID | 钉钉开放平台 > 应用详情 > 凭证与基础信息 | 否 |
#### Webhook 自定义机器人
| 参数 | 说明 | 获取方式 | 必填 |
|------|------|----------|------|
| `webhook_url` | Webhook 地址 | 钉钉群 > 群设置 > 智能群助手 > 添加自定义机器人 > 复制 Webhook | 是 |
| `webhook_secret` | 加签密钥 | 创建机器人时选择"加签"安全方式,复制 SEC 开头的密钥 | 否* |
> *如果安全设置选择了"加签"方式,则 webhook_secret 必填。
> 两种机器人的配置可以同时存在于同一个配置文件中,互不影响。
### 配置管理命令
```bash
# 初始化配置文件
python scripts/dingtalk.py config --init
# 查看当前配置
python scripts/dingtalk.py config --show
# 设置单个配置项
python scripts/dingtalk.py config --set app_key=dingxxxxxxxxxxxx
# 添加机器人
python scripts/dingtalk.py robot-add --name "技术告警群" --type webhook --webhook-token "token_xxx"
python scripts/dingtalk.py robot-add --name "内部通知" --type app --app-key dingxxx --app-secret xxx --robot-code robot-xxx
# 强制覆盖已存在的配置
python scripts/dingtalk.py config --init --force
```
### 命令行参数覆盖
配置文件中的值可以通过命令行参数临时覆盖:
```bash
python scripts/dingtalk.py text "测试消息" \
--users user001 \
--app-key dingxxxxxxxxxxxx \
--app-secret your-secret-key \
--robot-code robot-xxxxxx
```
---
## 消息类型详解
| 类型 | CLI 指令 | 模式 | 说明 |
|------|----------|------|------|
| 文本消息 | `text` | 单聊/群聊 | 纯文本,支持 @用户 |
| Markdown | `markdown` | 单聊/群聊 | 有限 Markdown 语法的富文本 |
| 链接消息 | `link` | 单聊/群聊 | 带缩略图的链接卡片 |
| ActionCard | `action-card` | 单聊/群聊 | 带按钮的交互卡片(单/多按钮) |
| 文件消息 | `file` | 仅单聊 | 发送文件,自动上传 |
| 图片消息 | `image` | 仅单聊 | 发送图片 |
| 语音消息 | `voice` | 仅单聊 | 发送语音 |
---
## 钉钉 Markdown 语法限制
钉钉的 Markdown 渲染器只支持标准 Markdown 的有限子集。
### 支持的语法
| 语法 | 写法 | 说明 |
|------|------|------|
| 标题 | `# 一级标题` ~ `###### 六级标题` | 正常支持 |
| 加粗 | `**粗体文字**` | 正常支持 |
| 链接 | `[链接文字](url)` | 正常支持 |
| 图片 | `![alt](图片url)` | 正常支持 |
| 无序列表 | `- 列表项` | 正常支持 |
| 有序列表 | `1. 列表项` | 正常支持 |
| 引用 | `> 引用文字` | 正常支持 |
### 不支持的语法(禁止使用)
以下语法在钉钉中**不会被渲染**,甚至可能导致显示异常:
- 水平分隔线:`---`、`***`、`___`
- 表格:`| col1 | col2 |`
- 代码块:`` ``` ``
- 行内代码:`` `code` ``
- 删除线:`~~text~~`
- 任务列表:`- [ ] item`
- 斜体:`*italic*`(不稳定)
- 嵌套列表:多级缩进列表(显示不稳定)
### 编写建议
1. 用 `#` ~ `####` 标题组织结构
2. 用 `- item` 无序列表展示条目
3. 用 `**重点**` 加粗强调关键信息
4. 用 `> 备注` 添加补充说明
5. 不要用分隔线,用标题或空行替代
6. 不要用表格,用列表格式替代
7. 在 CLI 中使用 `\n` 表示换行
---
## 错误码参考
### 企业内部机器人
| 错误码 | 说明 |
|--------|------|
| 0 | 成功 |
| -1 | 系统繁忙,请稍后重试 |
| 40001 | access_token 不存在或已过期 |
| 40002 | access_token 不合法 |
| 40004 | 无效的机器人(robotCode 错误) |
| 40007 | 无效的 openConversationId |
| 40008 | 无效的消息内容(msgParam 格式错误) |
| 40009 | 消息发送失败,用户不在该机器人可见范围 |
| 40010 | 消息发送失败,用户未与机器人建立会话 |
| 40014 | 无效的 userId |
| 40037 | 发送消息过于频繁,已触发限流 |
| 40056 | 无效的 agentId |
### Webhook 自定义机器人
| 错误码 | 说明 |
|--------|------|
| 0 | 成功 |
| 300001 | 无效的 token / 机器人不存在 |
| 310000 | 安全校验失败(关键词不匹配 / IP 不在白名单 / 签名错误 / 时间戳过期) |
| 302503 | 频率限制,每分钟超过 20 条 |
| 400013 | JSON 格式无效 |
---
## 注意事项与限制
### 企业内部机器人
#### 频率限制
- 每个应用每秒钟最多调用 **20 次** 消息发送接口
- 超出限制会返回错误码 `40037`
#### 用户限制
- 批量发送单聊消息时,`userIds` 每次最多 **100 个**
- 超过 100 个需分批发送
#### 会话前置条件
- 发送单聊消息前,用户需要先与机器人**建立会话**(用户主动给机器人发送过消息)
- 未建立会话的用户会收到错误码 `40010`
#### 文件上传
- 发送文件/图片/语音消息前,需要先通过 `/media/upload` 接口上传文件获取 `media_id`
- CLI 工具的 `file` 命令已自动集成上传流程
#### Token 管理
- `access_token` 有效期为 **7200 秒**(2 小时)
- 工具内置缓存机制,过期前 5 分钟自动刷新
- 不建议频繁调用 gettoken 接口
### Webhook 自定义机器人
#### 频率限制
- 每个机器人每分钟最多发送 **20 条** 消息
- 超出限制返回错误码 `302503`
#### 安全设置
- 创建机器人时必须至少选择一种安全方式:自定义关键词、IP 白名单、加签
- 使用加签时,时间戳与服务器时间差不能超过 **1 小时**
- 脚本内置加签逻辑,配置 `webhook_secret` 后自动签名
#### 消息范围
- Webhook 机器人只能在添加到的群聊中发送消息,**不支持单聊**
- `link` 和 `feedCard` 消息类型**不支持** @功能
#### Token 管理
- Webhook URL 中的 `access_token` 是固定的,无需刷新
- 只要机器人未被删除,URL 持续有效
### 通用
#### 消息内容
- Markdown 消息仅支持有限语法子集,见 [Markdown 语法限制](#钉钉-markdown-语法限制)
- 消息内容不宜过长,过长建议拆分或使用文件发送
- 企业内部机器人的 `msgParam` 需要序列化为 JSON 字符串后传入(脚本已自动处理)
#### API 域名
- 企业内部机器人(消息发送):`https://api.dingtalk.com`
- 企业内部机器人(gettoken、文件上传):`https://oapi.dingtalk.com`
- Webhook 自定义机器人:`https://oapi.dingtalk.com/robot/send`