CtrlK
BlogDocsLog inGet started
Tessl Logo

dingtalk-event

钉钉个人 IM 事件长连接监听、订阅与消费,覆盖消息接收、全部单聊/群消息、指定发送人、已读、撤回、表情回应和群生命周期,输出 NDJSON 到 stdout。Use when 用户提到 监听个人消息事件、监听所有单聊或群消息、被@消息、监听单聊或群消息、监听某人发送的消息、监听消息已读、监听消息撤回、监听消息贴表情或表情回应、监听群成员加入、监听群成员退出、监听群改名或群解散、实时接收钉钉事件、用事件驱动 Agent。命令前缀:dws event。

72

Quality

88%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

SKILL.md
Quality
Evals
Security

钉钉个人 IM 事件

只使用 dws event consume 建立个人消息事件长连接。用户要求实时监听、订阅、自动回复或驱动 Agent 时,不要写轮询脚本,不要用消息历史查询模拟事件。

运行方式

  • bus 后台进程持有对钉钉的个人 Stream 长连;consume 从 bus 读事件、按 NDJSON 打到 stdout。consume 只读,不发消息(回复用 dws chat message send)。
  • 没有 bus 时 consume 自动拉起;通常只跑 consume。
  • 一个组织一个 bus,可同时跑;同组织内多个 consume 共享一个 bus。
  • 非默认组织加全局 --profile <corpId 或 profile 名>;漏传会退回默认 profile 而失败。

Core commands

CommandPurpose
dws event list查看当前个人事件目录;不要把它当能力菜单主动展示
dws event schema <event_key> --flatten查看 Agent 使用的顶层业务字段 schema,默认 JSON
dws event consume <event_key> [event_key...] --flatten [flags]阻塞消费一个或多个兼容事件;事件写到 stdout,推荐 -f ndjson
dws event status --event <event_key>查看个人订阅、personal bus 和本地 consume
dws event stop <subscribe_id> --dry-run / --yes先预览,再确认取消个人订阅并停止对应本地消费
dws event stop --all --dry-run / --yes先预览,再确认清理当前身份下本地记录的全部个人订阅

区分两个 schema:dws event schema <event_key> 查事件输出字段;dws schema "event consume" 查 consume 命令入参(统一内嵌 ToolSpec,含 parameters + 位置参数)。source 是 reviewed command identity 的 provenance;event list/schemainterface_mode=localevent consume/status/stop 因同时编排远端订阅控制面与本地 bus 而是 interface_mode=composite,不要把 identity 与实现机制混为一谈。

Event catalog

事件码场景必填参数
user_im_message_receive_at当前用户被 @ 的消息
user_im_message_receive_o2o当前用户与指定用户的单聊消息--user--open-dingtalk-id
user_im_message_receive_group当前用户所在指定群聊/会话的消息--group
user_im_message_receive_user当前用户收到的指定用户发送的消息(单聊和群聊)--user--open-dingtalk-id
user_im_message_receive_o2o_all当前用户收到的所有单聊消息
user_im_message_receive_group_all当前用户收到的所有群聊消息
user_im_message_read_o2o指定单聊中当前用户发送的消息被已读--user--open-dingtalk-id
user_im_message_read_group指定群聊中当前用户发送的消息被已读--group
user_im_message_recall_o2o指定单聊中的消息被撤回--user--open-dingtalk-id
user_im_message_recall_group指定群聊中的消息被撤回--group
user_im_message_reaction_o2o指定单聊中的消息收到表情回应--user--open-dingtalk-id
user_im_message_reaction_group指定群聊中的消息收到表情回应--group
user_im_group_updated指定群聊的标题发生变更--group
user_im_group_member_added指定群聊有成员加入--group
user_im_group_member_exited指定群聊有成员退出--group
user_im_group_disbanded指定群聊被解散--group

只承认上表 16 个事件码。其它身份模式、应用凭证模式、非个人 IM 事件不在本 skill 范围内。

Command rules

  • 默认身份就是当前用户,不要额外加身份切换 flag。
  • 使用当前用户 OAuth 登录态;未登录或 token 失效时,引导用户执行 dws auth login
  • 不主动运行 dws event list 作为能力菜单;按用户意图直接选择上表事件。
  • 缺少必填 ID 时先解析或追问,不要猜测 ID。
  • 用户只给单聊对端人名时,先运行 dws aisearch person --keyword "<name>" --dimension name --format json 解析 userId;多候选必须让用户确认。
  • 企业内部 userId 使用 --user;用户明确提供 openDingtalkId,或目标是外部联系人、机器人、跨组织身份时,使用 --open-dingtalk-id
  • --user--open-dingtalk-id 严格二选一。不要把 openDingtalkId 填入 --user,不要自动猜测或转换身份类型;缺少外部目标的 openDingtalkId 时先追问。
  • “监听我和某人的单聊”使用 user_im_message_receive_o2o;“监听某人发给我的消息/监听某人发送的消息”使用 user_im_message_receive_user,后者覆盖该发送人的单聊和群聊消息。
  • 只有用户明确要求“所有单聊消息”或“所有群消息”时才使用 user_im_message_receive_o2o_all / user_im_message_receive_group_all;指定人或指定群仍使用范围更小的事件。
  • 用户只给群名时,先运行 dws chat search --query "<group>" --format json 解析 openConversationId;多候选必须让用户确认。
  • “监听群改名/群标题变更”使用 user_im_group_updated;“监听有人进群”使用 user_im_group_member_added;“监听有人退群”使用 user_im_group_member_exited;“监听群解散”使用 user_im_group_disbanded。群解散自测只能使用明确的测试群,并在执行解散操作前再次提示其不可逆影响。
  • 用户要求执行“撤回消息”时使用 dws chat;只有“监听/订阅消息撤回”才使用 dws event consume user_im_message_recall_*
  • 用户说“贴标签”且语义是给消息贴表情时,按消息表情回应事件处理,event key 使用 reaction
  • 正常 Agent 消费统一显式使用 --flatten -f ndjson。抓一条样本可用 --flatten --max-events 1 -f json--format 只控制 JSON 序列化,--flatten 才控制数据结构。
  • 同一目标、同一过滤条件的兼容事件优先放在一个 consume 命令中:用户类事件共享一个 --user--open-dingtalk-id,群类事件共享一个 --group,无目标事件可加入任一类组合。
  • 用户类与群类事件不能放进同一命令;不同用户、不同群或不同过滤条件必须启动多个 consume 进程。多事件命令不使用 --subscribe-id--rule--event-types--filter--foreground--force--debug-raw-events
  • 多事件共享 --query / --filter-json 时,所选事件必须全部是消息接收事件;已读、撤回、表情回应或群生命周期事件混入后不能使用消息过滤参数。
  • 监听非默认组织时带 --profile <corpId 或 profile 名>;漏传会退回默认 profile 而失败。
  • 自己发的消息不作为事件回来(isSelfLoop 过滤):边监听边 dws chat message send 回复不成环;测试投递用别人 / 机器人发(自发会看到 0 事件)。
  • --debug-raw-events 只用于联调确认服务端推送是否到达本地连接;正常任务不要使用。它和 --flatten 互斥,-f raw 也不能与 --flatten 同时使用。
  • 排查:consume 报 bus 启动失败 → 报错已带真实原因,先查 dws --profile <x> auth status(非默认组织带对 --profile);本地日志见 ~/.dws/events/<edition>/personal_stream/<hash>/bus.loghashdws event status 的 Workdir);有残留先用 dws event stop --all --dry-run 预览,确认后加 --yes 清理。看着"挂住"无输出多是误加了 --foreground(那是跑 bus、不打印事件),去掉即可。

订阅创建失败与重试预算

以下约束适用于上表全部 16 个事件以及多事件命令中的每一项,只治理 [event] ready 之前的订阅创建;ready 之后的 Stream 断线由长连接重连机制处理。

  • 0/2/1Agent/host 编排约束,不是 CLI 持久化硬总次数上限。每次 dws event consume 调用对每个逻辑订阅最多发送一次订阅创建 HTTP 请求,进程内不会自动重试。CLI 本地状态只持久化 in_flightcooldownterminal_hold 三种保护状态,不持久化或计算跨调用的 Agent/host 尝试次数。
  • 解析人名或群名、执行 event consume 以及后续 event status/stop 必须使用同一个 --profile。不得把其它 profile 下解析出的 userId、openDingtalkId 或 openConversationId 直接带入当前 profile 的订阅。
  • 同一逻辑订阅由当前 profile / 身份、event key、rule type、目标和过滤条件共同确定。subscribe_idtrace_id 以及重新启动进程都只是诊断或执行信息,不会生成新的逻辑操作;Agent/host 必须自行延续原编排预算。
  • Agent/host 收到 retryable=falsemax_additional_attempts=0,立即停止,不得自动重跑。
  • Agent/host 收到 retryable=truemax_additional_attempts=2,初次失败后最多再尝试 2 次;错误若给出 retry_after_secondsnext_retry_at,不得提前重试。
  • 未返回 retryable(即 retryable=unknown):Agent/host 使用 max_additional_attempts=1,最多补偿尝试 1 次;仍无法确认时停止并上报错误与 trace。
  • in_flight 表示同一逻辑订阅已有请求执行中;cooldownterminal_hold 表示当前被退避或终态保护。遇到这些状态不得递归调用 event consume、并行启动相同订阅或通过新 subId / trace 绕过;等待原请求或保护时间结束,同时由 Agent/host 继续维护自己的编排次数。
  • 多事件命令必须作为同一次原始操作治理。不得把失败事件拆成新的单事件命令、调整顺序或反复重启来重置预算;启动中任一项失败时,由 CLI 回滚本次已经创建的订阅。

本地保护状态运维

  • open 版默认状态文件为 ~/.dws/events/open/personal_stream/<identity_hash>/personal_subscription_attempts.json。设置 DWS_CONFIG_DIR 后配置根目录随之变化;其它 edition 使用对应 edition 目录,不固定为 open
  • identity 目录权限为 0700personal_subscription_attempts.jsonpersonal_subscription_attempts.lock 权限均为 0600
  • 连续 24h 没有失败后失败计数重置;terminal_hold 持续 1h。正常处理优先等待错误中的 next_retry_at,不要把删状态文件当成常规重试手段。
  • 紧急恢复时,先确认该 identity 没有正在创建订阅的进程;只删除 personal_subscription_attempts.json,不要删除 lock 文件。删除 JSON 会清空该 identity 的全部保护记录,不只影响一个事件。

Call flow

  1. 从用户意图选择事件码;人名或群名先解析成必填 ID。
  2. 需要了解字段时运行 dws event schema <event_key> --flatten,读取 schema.properties;此模式的 jq_root_path.
  3. 启动 dws event consume <event_key> [event_key...] ... --flatten -f ndjson。单事件等待 [event] ready event_key=<key> bus_pid=<pid> subscribe_id=<id>;多事件先记录每条 [event] subscription event_key=<key> subscribe_id=<id>,再等待 [event] ready event_count=<n> bus_pid=<pid>。不要用 sleep 猜测。
  4. stdout 每行是一个扁平事件 JSON;消息、动作及群成员加入/退出事件直接读取顶层业务字段。群标题变更和群解散只读取公共字段与 payload 中实际存在的字段。
  5. 需要确认监听状态时运行 dws event status --event <event_key>,查看 SubscriptionsConsumers
  6. 任务完成后优雅结束 consume;本次新建的订阅会自动取消。复用已有订阅或需要从外部主动取消时,先用 dws event stop <subscribe_id> --dry-run 预览,向用户确认后再加 --yes;临时测试可用 --max-events--duration 自动退出。

Subprocess contract

  • event consume 阻塞式长连接。stdout 只出事件;stderr 只出状态 / debug / 错误。
  • 就绪:单事件使用 [event] ready event_key=<key> bus_pid=<pid> subscribe_id=<id>;多事件在全部逻辑 consumer 就绪后使用 [event] ready event_count=<n> bus_pid=<pid>,其前每个事件各有一条 [event] subscription ...。父进程等对应 ready 行再处理 stdout;不要 --quiet
  • 退出:末行 [event] exited — received N event(s) in Xs (reason: limit|timeout|signal|bus_shutdown);受控退出码 0,失败非 0 无 exited 行。
  • stdin 关闭 = 停机:仅当 stdin 是管道且未设 --max-events/--duration 时生效;交互终端和 < /dev/null 不触发。用管道 stdin 又要常驻就喂 < <(tail -f /dev/null)
  • 正常事件处理持续读取 stdout 管道,不要改写为 --output-dir watcher。
  • 无界监听需外部进程管理;有界自测用 --max-events N--duration 10m
  • 订阅清理:本次新建的订阅任意干净退出即自动退订;--subscribe-id 复用的保留,--ephemeral 强制退订。优雅停用 SIGTERM、关 stdin,或外部先用 dws event stop <subscribe_id> --dry-run 预览、确认后加 --yes。不要 kill -9(跳过退订、泄漏服务端订阅)。
  • 批量清理先用 dws event stop --all --dry-run 预览,确认后加 --yes
  • 一个 consume 可监听多个兼容事件,并为每个事件建立独立订阅和逻辑 consumer;它们共享本机 bus、远程连接、输出和生命周期,仍按 event_type + subscribe_id 隔离。dws event stop <subscribe_id> 只移除对应事件,最后一个被移除后进程退出。

Examples

# 当前用户被 @ 的消息
dws event consume user_im_message_receive_at --flatten -f ndjson

# 当前用户与指定用户的单聊消息
dws event consume user_im_message_receive_o2o \
  --user test-user-001 \
  --flatten \
  -f ndjson

# 使用 openDingtalkId 监听外部联系人、机器人或跨组织身份的单聊消息
dws event consume user_im_message_receive_o2o \
  --open-dingtalk-id open-user-1 \
  --flatten \
  -f ndjson

# 指定群聊/会话消息
dws event consume user_im_message_receive_group \
  --group cidxxxxxxxx \
  --flatten \
  -f ndjson

# 指定发送人的消息(单聊和群聊)
dws event consume user_im_message_receive_user \
  --user test-user-001 \
  --flatten \
  -f ndjson

# 当前用户收到的所有单聊消息(仅在用户明确要求“所有”时使用)
dws event consume user_im_message_receive_o2o_all --flatten -f ndjson

# 当前用户收到的所有群聊消息(仅在用户明确要求“所有”时使用)
dws event consume user_im_message_receive_group_all --flatten -f ndjson

# 使用 openDingtalkId 监听指定发送人的消息
dws event consume user_im_message_receive_user \
  --open-dingtalk-id open-user-1 \
  --flatten \
  -f ndjson

# 指定单聊消息已读
dws event consume user_im_message_read_o2o \
  --user test-user-001 \
  --flatten \
  -f ndjson

# 指定群聊消息撤回
dws event consume user_im_message_recall_group \
  --group cidxxxxxxxx \
  --flatten \
  -f ndjson

# 指定单聊消息收到表情回应
dws event consume user_im_message_reaction_o2o \
  --user test-user-001 \
  --flatten \
  -f ndjson

# 指定群标题变更
dws event consume user_im_group_updated \
  --group cidxxxxxxxx \
  --flatten \
  -f ndjson

# 指定群有成员加入
dws event consume user_im_group_member_added \
  --group cidxxxxxxxx \
  --flatten \
  -f ndjson

# 指定群有成员退出
dws event consume user_im_group_member_exited \
  --group cidxxxxxxxx \
  --flatten \
  -f ndjson

# 指定群解散
dws event consume user_im_group_disbanded \
  --group cidxxxxxxxx \
  --flatten \
  -f ndjson

# 同一用户的单聊消息、已读和撤回(一个进程)
dws event consume \
  user_im_message_receive_o2o \
  user_im_message_read_o2o \
  user_im_message_recall_o2o \
  --user test-user-001 \
  --flatten \
  -f ndjson

# 同一群的消息和生命周期事件(一个进程)
dws event consume \
  user_im_message_receive_group \
  user_im_group_updated \
  user_im_group_disbanded \
  --group cidxxxxxxxx \
  --flatten \
  -f ndjson

# 有界自测
dws event consume user_im_message_receive_at \
  --duration 10m \
  --flatten \
  -f ndjson

# 抓一条样本
dws event consume user_im_message_receive_o2o \
  --user test-user-001 \
  --max-events 1 \
  --flatten \
  -f json

所有 *_o2o 命令和 user_im_message_receive_user 都可将 --user <userId> 替换为 --open-dingtalk-id <openDingtalkId>,但两个参数不能同时使用。

输出处理

  • dws event schema <event_key> --flatten 是 Agent 写解析逻辑的依据。
  • --flatten 模式的顶层 jq_root_path.;不传时为兼容存量脚本的 transport envelope,业务 payload 在 .data | fromjson
  • schema.properties 是业务字段列表,例如 contentsenderconversation_idmessage_idevent_time
  • Agent 命令已显式传 --flatten,消息接收、已读、撤回和表情回应事件直接读取顶层业务字段;不要对该模式再生成 fromjson 或内部 transport 路径。
  • 引用回复读取可选的 quoted_message;合并转发读取可选的 forward_messages 数组。两者保留内部消息的 message_id/conversation_id/sender/sender_open_dingtalk_id/content/create_time;不要通过“聊天记录”等本地化外层文案识别或拆分合并转发。
  • 群成员加入/退出事件读取顶层 conversation_idoperatoroperator_open_dingtalk_idmembersevent_timeoperator 是执行操作的人,members 是本次加入或退出的成员数组;成员项读取 nickopen_dingtalk_id。系统操作或成员自行退出时,操作人字段可能为空。
  • 群标题变更和群解散当前只承诺顶层 type/event_id/timestamp/subscribe_id/payload。读取 payload 时以实际键为准,不猜测群标题、操作者等尚未确认的字段;完整原始协议用 -f raw--debug-raw-events 排查。
  • 群自动回复使用事件顶层 conversation_id;单聊自动回复使用顶层 sender_open_dingtalk_id
  • 已读事件读取顶层 readerreader_open_dingtalk_idread_time;撤回事件读取 recallerrecaller_open_dingtalk_idrecall_time
  • 表情回应事件读取顶层 operatoroperator_open_dingtalk_idreaction_namereaction_textoperation_typeoperation_time
  • 图片、文件等媒体消息的 content 可能是可读描述;合并转发媒体的下载定位信息位于对应 forward_messages[].content。需要实际媒体文件时调用 dws chat message download-media

Topic index

TopicReferenceCoverage
IMreferences/event-im.md十六类个人 IM 事件命令、参数、生命周期、输出解析、自测和排障
Repository
DingTalk-Real-AI/dingtalk-workspace-cli
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.