Loading...
Loading...
Connect OpenClaw AI agents to DingTalk with message handling, document operations, calendar, todos, and AI cards
npx skill4agent add aradotso/hermes-skills dingtalk-openclaw-connectorSkill by ara.so — Hermes Skills collection.
openclaw -vnpm install -g openclawnpx -y @dingtalk-real-ai/dingtalk-connector installopenclaw gateway restartnpm install -g @dingtalk-real-ai/dingtalk-connector# DingTalk bot credentials (obtained during authorization)
DINGTALK_CLIENT_ID=your_client_id
DINGTALK_CLIENT_SECRET=your_client_secret
DINGTALK_ROBOT_CODE=your_robot_code
# Optional: Multi-agent routing
DINGTALK_AGENT_MAPPING='{"bot_code_1":"agent_1","bot_code_2":"agent_2"}'
# Optional: Access control
DINGTALK_PRIVATE_CHAT_POLICY=whitelist # whitelist|blacklist|all
DINGTALK_GROUP_CHAT_POLICY=all # whitelist|blacklist|all
DINGTALK_WHITELIST=user_id_1,user_id_2// In OpenClaw channel config
{
"privateChatPolicy": "whitelist", // Only whitelisted users
"groupChatPolicy": "all", // All groups
"whitelist": ["user_123", "user_456"],
"blacklist": []
}allwhitelistblacklist// Agent receives message context
interface MessageContext {
conversationId: string;
senderId: string;
senderName: string;
content: {
text?: string;
images?: Array<{ downloadCode: string; url: string }>;
files?: Array<{ fileName: string; downloadCode: string }>;
};
isGroupChat: boolean;
atUsers?: string[];
}// Agent action
{
"action": "sendMessage",
"params": {
"conversationId": "cid_xxx",
"content": "Hello from OpenClaw!"
}
}{
"action": "sendMessage",
"params": {
"conversationId": "cid_xxx",
"content": "## Report\n@user_123 please review",
"format": "markdown",
"atUsers": ["user_123"]
}
}{
"action": "sendMessage",
"params": {
"conversationId": "cid_xxx",
"imageUrl": "https://example.com/image.png"
// Or local path: "imagePath": "/path/to/image.png"
}
}// Enable in channel config
{
"enableAICard": true,
"streamingMode": "typewriter" // typewriter effect
}{
"action": "createDocument",
"params": {
"title": "Meeting Notes",
"content": "# Agenda\n- Item 1\n- Item 2",
"spaceId": "space_xxx" // optional
}
}{
"action": "appendDocument",
"params": {
"documentId": "doc_xxx",
"content": "\n## New Section\nAdditional notes..."
}
}{
"action": "searchDocuments",
"params": {
"keyword": "meeting",
"maxResults": 10
}
}{
"action": "sendDing",
"params": {
"receiverUserIds": ["user_123", "user_456"],
"content": "Urgent: Server down!",
"remindType": "DING_SMS" // DING_NOTICE or DING_SMS
}
}{
"action": "createTodo",
"params": {
"subject": "Review PR #123",
"description": "Check code quality",
"dueTime": "2026-05-20T17:00:00Z",
"executorIds": ["user_123"]
}
}{
"action": "getTodos",
"params": {
"status": "PENDING", // PENDING|DONE
"startDate": "2026-05-01",
"endDate": "2026-05-31"
}
}{
"action": "createCalendarEvent",
"params": {
"calendarId": "cal_xxx",
"summary": "Team Sync",
"startTime": "2026-05-20T14:00:00+08:00",
"endTime": "2026-05-20T15:00:00+08:00",
"location": "Conference Room A",
"attendees": [
{ "userId": "user_123" },
{ "userId": "user_456" }
]
}
}{
"action": "searchCalendarEvents",
"params": {
"calendarId": "cal_xxx",
"startTime": "2026-05-20T00:00:00+08:00",
"endTime": "2026-05-21T00:00:00+08:00"
}
}{
"action": "checkAvailability",
"params": {
"userIds": ["user_123", "user_456"],
"startTime": "2026-05-20T14:00:00+08:00",
"endTime": "2026-05-20T15:00:00+08:00"
}
}{
"action": "createAITable",
"params": {
"name": "Customer Database",
"fields": [
{ "name": "Name", "type": "TEXT" },
{ "name": "Email", "type": "TEXT" },
{ "name": "Status", "type": "SINGLE_SELECT", "options": ["Active", "Inactive"] }
]
}
}{
"action": "insertTableRow",
"params": {
"tableId": "tbl_xxx",
"fields": {
"Name": "John Doe",
"Email": "john@example.com",
"Status": "Active"
}
}
}{
"action": "queryTableRows",
"params": {
"tableId": "tbl_xxx",
"filter": {
"Status": "Active"
},
"maxResults": 50
}
}{
"action": "submitJournal",
"params": {
"type": "daily",
"date": "2026-05-20",
"content": "## Completed\n- Feature A\n- Bug fix B\n\n## Tomorrow\n- Feature C"
}
}{
"action": "getJournals",
"params": {
"type": "weekly",
"startDate": "2026-05-01",
"endDate": "2026-05-15"
}
}# In .env or OpenClaw config
DINGTALK_AGENT_MAPPING='{
"robot_code_hr": "hr_agent",
"robot_code_it": "it_support_agent",
"robot_code_sales": "sales_agent"
}'# openclaw.config.yaml
agents:
hr_agent:
name: HR Assistant
model: gpt-4
systemPrompt: You are an HR assistant handling employee queries
it_support_agent:
name: IT Support
model: gpt-4
systemPrompt: You provide IT technical support
sales_agent:
name: Sales Helper
model: gpt-4
systemPrompt: You assist with sales inquiries and CRM// Agent receives all group messages where bot is @mentioned
// Auto-respond with context-aware answers
async function handleMessage(context: MessageContext) {
const { content, isGroupChat, atUsers } = context;
if (isGroupChat && !atUsers?.includes(botUserId)) {
return; // Ignore if not @mentioned
}
const response = await generateResponse(content.text);
return {
action: "sendMessage",
params: {
conversationId: context.conversationId,
content: response
}
};
}// Search docs and create summary
async function searchAndSummarize(query: string) {
// 1. Search documents
const docs = await executeAction({
action: "searchDocuments",
params: { keyword: query, maxResults: 5 }
});
// 2. Generate summary
const summary = await summarize(docs);
// 3. Create new doc with results
return executeAction({
action: "createDocument",
params: {
title: `Search Results: ${query}`,
content: summary
}
});
}// Find available slot and create event
async function scheduleMeeting(attendeeIds: string[], duration: number) {
const now = new Date();
const nextWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
// 1. Check availability
const availability = await executeAction({
action: "checkAvailability",
params: {
userIds: attendeeIds,
startTime: now.toISOString(),
endTime: nextWeek.toISOString()
}
});
// 2. Find first free slot
const freeSlot = findFreeSlot(availability, duration);
// 3. Create event
return executeAction({
action: "createCalendarEvent",
params: {
summary: "Team Meeting",
startTime: freeSlot.start,
endTime: freeSlot.end,
attendees: attendeeIds.map(id => ({ userId: id }))
}
});
}// Create todo from message command
async function createTaskFromMessage(message: string, conversationId: string) {
// Parse: "todo: Review PR #123 by Friday"
const match = message.match(/todo:\s*(.+?)\s+by\s+(.+)/i);
if (!match) return;
const [, task, deadline] = match;
// Create todo
const todo = await executeAction({
action: "createTodo",
params: {
subject: task,
dueTime: parseDeadline(deadline)
}
});
// Confirm in chat
return executeAction({
action: "sendMessage",
params: {
conversationId,
content: `✅ Task created: ${task}\n📅 Due: ${deadline}`
}
});
}openclaw gateway statusopenclaw gateway restart# Check if config exists
openclaw config listopenclaw gateway logs// Ensure enabled in config
{
"enableAICard": true,
"streamingMode": "typewriter"
}DINGTALK_AGENT_MAPPINGopenclaw.config.yamlcalendarId40014600209000271006# Send test message to bot in DingTalk
# Expected: Bot responds with AI-generated reply in card format// Test document creation
// In DingTalk: @bot create a document titled "Test"
// Test todo
// In DingTalk: @bot remind me to review code tomorrow
// Test search
// In DingTalk: @bot search for meeting notes from last week