first commit

This commit is contained in:
2026-09-02 11:44:52 +08:00
commit 0c8fa2653e
309 changed files with 57278 additions and 0 deletions
@@ -0,0 +1,187 @@
# chat-bot:机器人与 Webhook
> 返回入口:[chat.md](../chat.md)
## 适用场景
用于搜索机器人、机器人发送/撤回消息、Webhook 告警、机器人加入/移出群,以及给机器人发单聊消息。
<!-- dws-intent: chat.send.advanced -->Bot/Webhook 默认统一使用 `dws chat +messages-send`,通过
`--as bot|webhook` 选择身份;原子发送命令只保留 Shortcut 未发布字段的底层 fallback。
## 必读约束
- 用户明确要求“用机器人/机器人身份/robot”发送时,使用
`dws chat +messages-send --as bot --robot-code <robotCode>`;不得改成当前用户身份。
- `chat bot search` 只返回我创建的机器人,没有 `openDingTalkId`;给机器人发单聊必须用 `chat bot find`
- 机器人发群消息前需确认机器人已在群中;报“机器人不存在”时先 `group members add-bot`
- `send-by-bot` 支持 Markdown、图片 URL 和文件,具体参数见下方消息类型路由。
- 机器人在群聊中引用回复已有消息时,使用原子命令 `send-by-bot --reply --ref-sender`;该能力仅支持 Markdown,不走 `+messages-reply` 的当前用户身份。
- 公网图片 URL 使用 `--msg-type image --image-url`,按图片消息发送。
- 本地图片和其他本地文件一样使用 `--msg-type file --file-path`,由 CLI 上传并按文件附件发送。
- 群聊传 `--group`;单聊可传 `--users``--open-dingtalk-ids` 或两者组合。
- Markdown 必须同时传 `--title``--text`;需要稳定换行时用空行分隔段落。若以转义形式组织文本,写 `\n\n`,不要只写 `\n`
- `recall-by-bot` 使用 `processQueryKey`,不是 `openMessageId`
- Bot 多群文本/Markdown 直接使用 `+messages-send --groups <cid...>`
`--groups-file <工作目录内相对文件>`;最多 100 个稳定 IDRuntime 去重并返回
`im.batch-write.v1` 逐目标 ledger。
- `+messages-send` 的 Bot 路由和 Webhook 没有与 current-user 等价的文件、图片、音视频发送接口;
机器人富媒体必须使用原子 `chat message send-by-bot`,不得转成文本或换身份静默发送。
## 命令明细
### 机器人搜索
| 命令 | 范围 | 返回 openDingTalkId | 典型触发词 |
|------|------|---------------------|------------|
| `chat bot search` | 仅当前用户自己创建的机器人 | 否 | “我的机器人”“我创建的机器人” |
| `chat bot find` | 当前用户可用的全部机器人(含他人/官方) | 是 | “找机器人”“搜索机器人”“给机器人发单聊” |
```bash
dws chat bot search --page 1 --size 10 --name "日报"
dws chat bot find --query "日报" --limit 20
dws chat bot find --query "日报" --limit 20 --cursor <nextCursor>
```
`bot find` 翻页时 `cursor` 必须使用上次返回的 `nextCursor` 字符串原值,不要传 `"0"` 或数字字面量。
### 机器人发送与撤回
多群正式入口:
```bash
dws chat +messages-send --as bot --robot-code <robot-code> \
--groups <openConversationId1>,<openConversationId2> \
--markdown "## 通知\n\n请提交周报" --format json
```
读取 `requestedCount/succeededCount/failedCount/results/failures`;unknown 或失败目标不自动重发。
#### `dws chat message send-by-bot`(底层 fallback
普通文本/Markdown、群聊/批量单聊和 @ 已由 `+messages-send --as bot` 覆盖。只有 Shortcut
缺失真实必需字段且精确 leaf Schema 允许时才使用以下原子命令。
```bash
# 群聊
dws chat message send-by-bot --robot-code <robot-code> --conversation-id <openConversationId> --title "日报" --text "## 今日完成\n\n- 事项 A\n\n- 事项 B"
dws chat message send-by-bot --robot-code <robot-code> --conversation-id <openConversationId> --reply <openMessageId> --ref-sender <senderOpenDingTalkId> --text "收到"
dws chat message send-by-bot --robot-code <robot-code> --conversation-id <openConversationId> --msg-type image --image-url "https://example.com/image.png"
dws chat message send-by-bot --robot-code <robot-code> --conversation-id <openConversationId> --msg-type file --file-path ./report.pdf
# 单聊 userId
dws chat message send-by-bot --robot-code <robot-code> --users userId1,userId2 --title "提醒" --text "请提交周报"
# 单聊 openDingTalkId
dws chat message send-by-bot --robot-code <robot-code> --open-dingtalk-ids openDingTalkId1,openDingTalkId2 --title "提醒" --text "请提交周报"
# 群聊 @ 人
dws chat message send-by-bot --robot-code <robot-code> --group <openConversationId> --at-user-ids userId1,userId2 --title "提醒" --text "@userId1 @userId2 请查收"
dws chat message send-by-bot --robot-code <robot-code> --group <openConversationId> --at-open-dingtalk-ids openDingTalkId1,openDingTalkId2 --title "提醒" --text "@openDingTalkId1 @openDingTalkId2 请查收"
dws chat message send-by-bot --robot-code <robot-code> --group <openConversationId> --at-all --title "通知" --text "请所有人注意"
```
关键 flags
| Flag | 说明 |
|------|------|
| `--robot-code` | 机器人 Code,必填 |
| `--conversation-id` | 群聊 openConversationId`--group` 为兼容别名 |
| `--users` | 单聊 userId 列表,逗号分隔,最多 20 个 |
| `--open-dingtalk-ids` | 单聊 openDingTalkId 列表 |
| `--msg-type` | `markdown``image``file`;省略时为 Markdown;公网图片使用 `image --image-url`,本地图片和文件使用 `file --file-path` |
| `--text` | Markdown 消息内容,Markdown 模式必填;换行用空行,转义表示为 `\n\n` |
| `--title` | 普通 Markdown 消息标题;引用回复省略时由 CLI 从正文生成 |
| `--image-url` | 公网图片 URL`--msg-type image` 时必填 |
| `--file-path` | 本地图片或文件路径,`--msg-type file` 时由 CLI 上传并按文件附件发送 |
| `--at-user-ids` / `--at-open-dingtalk-ids` | 群聊 @ 指定成员,正文需含对应 `@id` 文本 |
| `--at-all` | 群聊 @所有人 |
| `--reply` | 被引用消息的 `openMessageId`;仅群聊 Markdown,必须与 `--ref-sender` 同时使用 |
| `--ref-sender` | 被引用消息发送者的 `openDingTalkId`;仅群聊 Markdown,必须与 `--reply` 同时使用 |
引用回复不会设置 `msgType=reply`CLI 在普通群消息参数顶层透传 `referenceOpenMessageId``srcMsgSendOpenDingTalkId`。只传其中一个参数、用于单聊或用于图片/文件消息都会在本地失败。
#### `dws chat message recall-by-bot`
```bash
dws chat message recall-by-bot --robot-code <robot-code> --group <openConversationId> --keys <processQueryKey>
dws chat message recall-by-bot --robot-code <robot-code> --keys key1,key2
```
群聊撤回传 `--group`;单聊撤回不传 `--group``--keys` 来自 `send-by-bot` 返回的 `processQueryKey`
### Webhook
默认使用:
```bash
dws chat +messages-send --as webhook --webhook-token <webhook-token> --title "告警" --text "CPU 超 90% @10" --at-all
```
以下是底层 fallback,不作为默认选路:
```bash
dws chat message send-by-webhook --token <webhook-token> --title "告警" --content "CPU 超 90% @10" --at-all
dws chat message send-by-webhook --token <webhook-token> --title "test" --content "hi @118785" --at-users 118785
```
关键规则:
- `--token``--title``--content` 必填。
- `--at-all``--content` 中需包含 `@10`
- `--at-users``--at-mobiles` 时,`--content` 中需包含对应 `@userId``@手机号`,否则 @ 不生效。
### 机器人进群
| 命令 | 用途 | 必填参数 |
|------|------|----------|
| `group members add-bot` | 将自定义机器人加入群 | `--id` `--robot-code` |
| `group members remove-bot` | 从群移除机器人 | `--id` `--bot-id` |
| `+chat-bots` | 查看群内机器人列表 | `--group <群名或openConversationId>`;自然群名内部唯一解析 |
```bash
dws chat group members add-bot --id <openConversationId> --robot-code <robot-code>
dws chat +chat-bots --group "项目群"
dws chat group members remove-bot --id <openConversationId> --bot-id <openBotId>
```
## 常见工作流
### 机器人发消息后撤回
```bash
dws chat bot search --name "日报" --format json
dws chat +messages-send --as bot --robot-code <robot-code> --group <openConversationId> --title "日报" --markdown "## 今日完成\n\n- 事项 A\n\n- 事项 B" --format json
dws chat message recall-by-bot --robot-code <robot-code> --group <openConversationId> --keys <processQueryKey> --format json
```
### 机器人不在群内时先邀请再发送
```bash
dws chat bot search --name "日报" --format json
dws chat group members add-bot --id <openConversationId> --robot-code <robot-code> --format json
dws chat +messages-send --as bot --robot-code <robot-code> --group <openConversationId> --title "通知" --text "内容" --format json
```
### 给机器人发单聊
```bash
dws chat bot find --query "玉澜" --format json
dws chat message send --open-dingtalk-id <openDingTalkId> --content "你好" --format json
```
### 机器人 @ 指定人
```bash
dws aisearch person --query "张三" --dimension name --format json
dws chat +messages-send --as bot --robot-code <robot-code> --group <openConversationId> --at-user-ids userId1 --title "提醒" --text "@userId1 请查收" --format json
```
## 常见错误与回退
- 机器人单聊没有 openDingTalkId:改用 `chat bot find`,不要用 `bot search`
- 机器人发群消息报“机器人不存在”:先 `group members add-bot`
- 撤回失败:确认使用 `processQueryKey`,不是 `openMessageId`
- 机器人引用回复失败:确认目标是群聊 Markdown,且 `--reply` 来自被引用消息的 `openMessageId``--ref-sender` 来自同一消息的发送者 `openDingTalkId`
- @ 不生效:检查正文是否包含 `@userId` / `@openDingTalkId` / `@10`
- 需要 Bot 图片/文件/音视频:停止并说明当前身份矩阵不支持;只有用户明确同意改为当前用户身份时,才重新确认目标和内容。
@@ -0,0 +1,154 @@
# chat-conversation:会话状态、红点、置顶与分组
> 返回入口:[chat.md](../chat.md)
## 适用场景
用于获取会话基础信息、全部会话/置顶会话列表、会话置顶、免打扰、隐藏、红点、已读未读、清空聊天记录、自定义会话分组和智能会话分组。
- <!-- dws-intent: chat.conversation.list-top -->查看置顶会话默认使用 `dws chat +conversation-list-top`
原子 `list-top-conversations` 只在需要原始响应时作为 fallback。
- <!-- dws-intent: chat.read.conversation -->取得目标会话后读取或导出消息记录,默认使用 `dws chat +chat-messages`
可附带非必填的 `--sender-query` 解析姓名:唯一解析成功后按 `senderId` 筛选同一次读取结果;
解析失败、不完整或存在歧义时抑制未过滤消息并返回 `sender_resolution_failed`。不要回到原子
`message list`,也不要补跑 `+search-msg`。直接条件检索优先使用 `+search-msg`
## 必读约束
- 会话状态类命令通常需要 `openConversationId`。群聊只用 `+chat-search --query` 获取唯一候选,单聊可由 `chat conversation-info --user/--open-dingtalk-id` 获取。
- `set-top` 是会话置顶;`message set-top-msg` 是会话内消息置顶,二者不能混用。
- `clear-messages` 只清空当前用户视角的消息,不影响其他成员。
- 智能分组规则中的成员使用 openDingTalkId;如果用户只给姓名,先用 `aisearch person --dimension name` 获取。
## 命令明细
### 会话基础信息
```bash
dws chat conversation-info --group <openConversationId> --format json
dws chat conversation-info --user <userId> --format json
dws chat conversation-info --open-dingtalk-id <openDingTalkId> --format json
```
`--group``--user``--open-dingtalk-id` 互斥且必须指定一个。文件/音视频发送不再依赖调用方读取 spaceId;直接用 `message send --msg-type file|audio|video --file`
### 会话列表与红点
| 命令 | 用途 | 参数 |
|------|------|------|
| `+conversation-list` | 获取当前用户会话 | 要求“全部”时加 `--page-all`;检查 `complete` / `failures` |
| `+chat-list` | 列出当前用户会话(默认群聊,可选单聊) | 默认只返回群聊;`--types group,p2p` 可包含单聊;要求全部时加 `--page-all`,合并去重后再过滤类型 |
| `+chat-list-all` | 获取当前用户加入的全部群 | 要求全部时加 `--page-all`;沿数字 `nextCursor` 去重聚合 |
| `+my-groups` | 获取并投影当前用户加入的群 | 要求全部时加 `--page-all`;读完后再应用 `--type` 本地过滤 |
| `+conversation-list-top` | 获取置顶会话列表 | 可选 `--limit` `--cursor` `--exclude-muted`;使用稳定 `conversations[]` |
| `message list-unread-conversations` | 获取未读会话列表 | 可选 `--count` `--exclude-muted` |
| `clear-red-point` | 清除指定会话红点 | `--conversation-id`,别名 `--id` / `--chat` |
| `clear-all-red-point` | 清除所有会话红点,一键全部已读 | 无参数 |
翻页时,`hasMore=true` 用返回的 `nextCursor` 作为下次 `--cursor`。Shortcut 全量读取应检查
`complete``stopReason``failures`;达到 `--page-limit` 时会保留可继续的 `nextCursor`
### 会话置顶与通知
| 命令 | 用途 | 必填参数 |
|------|------|----------|
| `set-top` | 设置/取消会话置顶 | `--conversation-id`;默认置顶,`--off` 取消 |
| `mute` | 开启/关闭会话免打扰 | `--conversation-id`;默认开启,`--off` 关闭 |
| `hide` | 隐藏会话 | `--conversation-id` |
| `mute-at-all` | 关闭/恢复 @所有人通知 | `--conversation-id`;默认关闭,`--off` 恢复;必须先开启会话总免打扰 |
| `mute-red-envelope` | 关闭/恢复红包通知 | `--conversation-id`;默认关闭,`--off` 恢复;必须先开启会话总免打扰 |
若连续操作两个子开关,优先操作红包通知;恢复 @所有人通知后,平台可能清除子开关所需的
总免打扰状态,此时要先重新开启总免打扰,再操作红包通知。
```bash
dws chat set-top --conversation-id <openConversationId>
dws chat set-top --conversation-id <openConversationId> --off
dws chat mute --conversation-id <openConversationId>
dws chat mute --conversation-id <openConversationId> --off
dws chat hide --conversation-id <openConversationId>
```
### 已读未读与清理
| 命令 | 用途 | 必填参数 |
|------|------|----------|
| `mark-unread` | 标记指定会话为未读 | `--conversation-id` |
| `mark-read` | 将指定消息及之前消息标记为已读 | `--conversation-id` `--message-id` |
| `clear-messages` | 清空当前用户指定会话的消息 | `--conversation-id` |
```bash
dws chat mark-unread --conversation-id <openConversationId>
dws chat mark-read --conversation-id <openConversationId> --message-id <openMessageId>
dws chat clear-messages --conversation-id <openConversationId>
```
### 会话分组
| 命令 | 用途 | 必填参数 |
|------|------|----------|
| `category list` | 获取用户自定义会话分组 | 无 |
| `category list-conversations` | 拉取指定分组下会话 | `--category-id`,可选 `--exclude-muted` |
| `category list-by-conv` | 拉取指定会话所属的用户自定义会话分组 | `--group` |
| `category batch-info` | 批量拉取用户自定义会话分组信息 | `--category-ids` |
| `category create` | 创建会话分组 | `--title` |
| `category create-smart` | 创建智能会话分组,可按群名称关键词和群内成员匹配 | `--name`,可选 `--keywords` `--members` |
| `category delete` | 删除会话分组 | `--category-id` |
| `category rename` | 修改分组名称 | `--category-id` `--title` |
| `category add-conv` | 将会话加入分组 | `--group` `--category-ids` |
| `category remove-conv` | 将会话移出分组 | `--group` `--category-ids` |
```bash
dws chat category list
dws chat category list-by-conv --group <openConversationId>
dws chat category batch-info --category-ids 123,456
dws chat category create --title "工作群"
dws chat category create-smart --name "重点群" --keywords "重点,项目" --members openDingTalkId1,openDingTalkId2
dws chat category add-conv --group <openConversationId> --category-ids 123,456
```
`create-smart``--keywords` 是群名称关键词列表,`--members` 是群内成员 openDingTalkId 列表;两者可单独使用,也可组合使用。
## 常见工作流
### 获取单聊会话 ID 后置顶
```bash
dws aisearch person --query "张三" --dimension name --format json
dws chat conversation-info --user <userId> --format json
dws chat set-top --conversation-id <openConversationId> --format json
```
### 查看置顶会话并拉消息
```bash
dws chat +conversation-list-top --limit 100 --format json
dws chat +chat-messages --group <openConversationId> --time "2026-03-10 00:00:00" --direction older --format json
```
### 会话分组
```bash
dws chat category create --title "重点项目" --format json
dws chat category add-conv --group <openConversationId> --category-ids <categoryId> --format json
dws chat category list-by-conv --group <openConversationId> --format json
dws chat category batch-info --category-ids <categoryId> --format json
dws chat category list-conversations --category-id <categoryId> --format json
```
### 智能会话分组
```bash
dws aisearch person --query "张三" --dimension name --format json
dws chat category create-smart --name "项目组" --keywords "项目,开发" --format json
dws chat category create-smart --name "团队群" --members openDingTalkId1,openDingTalkId2 --format json
dws chat category create-smart --name "重点群" --keywords "重点" --members openDingTalkId1 --format json
```
## 常见错误与回退
- 用户说“置顶消息”:用 `message set-top-msg`,不是 `chat set-top`
- 用户说“置顶会话”:设置/取消用 `chat set-top`,查看列表用 `+conversation-list-top`
- 单聊没有会话 ID:先 `conversation-info --user``--open-dingtalk-id`
- 清空聊天记录前必须确认目标会话;该操作只影响当前用户视角。
- 智能分组没有匹配条件:至少确认分组名称;关键词和成员规则不明确时先向用户确认,不要自行猜成员。
@@ -0,0 +1,144 @@
# group-admin:群创建、成员写入与管理
> 返回入口:[DingTalk Chat Skill](../../SKILL.md)
用于建群、修改群资料、成员增删、邀请卡片分享、群主和管理员、禁言、公告、群设置、
入群审批、群身份、退出、解散和升级外部群。只读群发现、成员读取和邀请链接使用
[group-discovery.md](group-discovery.md)。
## 安全与目标
- 群目标统一使用当前 profile 下真实 `openConversationId`;支持自然群名的 Shortcut 由 CLI
唯一解析,多候选时停止。
- 解散群、踢人、转让群主、禁言、管理员和外部群升级都是高影响操作;以最终 Runtime gate
和精确 leaf Schema 为准确认对象、动作与影响。
- 所有自然成员和群主必须先完成唯一解析并按稳定 ID 去重,再开始任何写入;不得边解析边
产生部分副作用。
- 群公告会触达成员;`notice edit` 是整体替换,必须有完整新正文。
## 建群与基础资料
<!-- dws-intent: chat.create.group -->基础建群使用 `dws chat +chat-create`。已知成员 ID 传 `--users`
姓名/花名传 `--member-query`;群主默认当前用户,也可传 `--owner-open-dingtalk-id`
`--owner-query`。任一自然身份未唯一解析时,创建前整体停止。
```bash
dws chat +chat-create --name "项目冲刺群" --member-query "测试用户甲,测试用户乙" --format json
dws chat +chat-create --name "合作群" --member-query "测试用户甲" \
--owner-query "测试用户乙" --type EXTERNAL --format json
```
修改群名称优先使用接受群名或稳定 ID 的 `+chat-update`
```bash
dws chat +chat-update --group <群名或openConversationId> --name "新群名" --format json
```
群头像和管理员级群开关使用 `+chat-update-icon``+chat-update-settings`;只有 Shortcut
尚未发布真实必需字段时才评估原子 `group rename/update-icon/update-settings`
原子 `chat group create` 只用于 `+chat-create` 未发布的真实底层字段,并先读取精确 leaf
Schema。普通内部/外部群、话题群和显式群主已经由 `+chat-create` 覆盖,不回流到手工
`aisearch → group create` 链路。
## 成员与机器人写入
| 动作 | 入口与关键参数 |
|---|---|
| 添加成员 | `group members add --id <cid> --users <userIds>` |
| 移除成员 | `group members remove --id <cid> --users <userIds>` |
| 添加已知机器人 | `+chat-add-bot` 或精确原子 `group members add-bot` |
| 查看群内机器人 | `+chat-bots --group <群名或cid>` |
| 移除群内机器人 | `+chat-remove-bot` 或精确原子 `group members remove-bot` |
普通成员增删的 `--users` 只接受组织 `userId`,必须来自真实人员解析结果;不得把
`+chat-members-list` / `+chat-members-get` 返回的 `openDingTalkId` 直接传入。添加已知机器人
使用 `robotCode`;移除机器人使用当前群 `+chat-bots` 返回的真实 `openBotId`,两者不能互换。
缺少 `openBotId` 时在同一流程中先执行 `+chat-bots`,不必额外读取群发现 reference。只有需要
搜索未知机器人、区分 `bot search` / `bot find`、机器人发送或撤回、Webhook 时,才读取
[chat-bot.md](chat-bot.md)。
## 邀请卡片、群主、管理员与禁言
邀请链接只读走 `+chat-invite-url`。实际分享邀请卡片使用 `group share-invite``--source`
是被分享群,接收端在 `--target` 会话和 `--receiver` 单聊用户之间二选一。
```bash
dws chat group share-invite --source <sourceCid> --target <targetCid> --format json
dws chat group share-invite --source <sourceCid> --receiver <openDingTalkId> --format json
```
| 动作 | 入口与关键参数 |
|---|---|
| 转让群主 | `+chat-transfer-owner --group <cid> --new-owner <稳定ID>` |
| 设置/取消管理员 | `group set-admin --group <cid> --users <ids> [--off]` |
| 全员禁言/解除 | `group-mute --group <cid> [--off]` |
| 成员禁言/解除 | `+chat-mute-member``group-mute-member` |
| 查询禁言配置 | `group get-mute-config --group <cid>` |
原子 `group-mute-member --mute-time` 单位为毫秒。不要用展示名称代替稳定用户 ID,也不要
在未确认影响时执行转让、踢人或禁言。
## 群设置与当前用户偏好
管理员级群开关使用 `+chat-update-settings` 或原子 `group update-settings`。常见 settingKey
包括 `authority``joinValidation``onlyAdminCanAtAll``searchable`
`addFriendForbidden``onlyAdminCanDING``onlyAdminCanPinMsg`
`onlyAdminCanSendFile``groupEmailDisabled``groupLiveAuthority`
`groupBillAuthority`;只修改用户明确要求的字段。
新成员历史消息可见范围使用 `group set-history --group <cid> --option <值>``option` 只取
精确 leaf Schema 发布值,不按自然语言猜枚举。
当前登录用户自己的置顶、免打扰、群昵称和群备注使用 `group user-settings query/set`
不是管理员群开关。单个群昵称/备注优先 `group update-nick/update-alias`
```bash
dws chat group user-settings query --groups <cid1>,<cid2> --format json
dws chat group user-settings set \
--items '[{"openConversationId":"cid1","top":true,"mute":false}]' --format json
```
批量设置只传本次要改的字段;空字符串清除昵称或备注,不补用户未要求的值。
## 群公告
| 动作 | 原子入口 |
|---|---|
| 发布公告 | `group notice create --group <cid> --content <完整Markdown>` |
| 修改公告 | `group notice edit --group <cid> --notice-id <id> --content <完整Markdown>` |
| 查询公告 | `group notice get/list` |
定时公告 `--run-at` 使用带时区时间;`notice list --scheduled` 查询待发布公告。分页时沿真实
`nextPageCursor` 继续。修改前必须取得完整替换正文,不把增量片段当整篇公告。
## 入群审批与群身份
先用 `group list-join-validations` 取得真实 `record-id/applicant/inviter`,再执行
`group audit-join-validation``+chat-audit-join`。审批状态只使用精确 leaf Schema 发布值。
群身份使用 `group-role` / `+chat-role-*`
- `list/add/update/remove` 管理身份定义;
- `set-user/remove-user/query-user` 管理成员身份;
- `openRoleId` 必须来自真实身份列表。
覆盖或清除成员身份前确认用户、群和完整角色集合,不能用展示名称猜 `openRoleId`
## 退出、解散与外部群升级
- 当前用户退出群:`+chat-quit` 或精确原子 `group quit`
- 解散群:`group dismiss`,不可逆。
- 普通群升级外部群:`group upgrade-to-external`,不可逆。
这些动作必须以最终 Runtime gate 为准,不把示例中的确认参数当固定事实。
## 完成与错误
- 创建或更新后保留真实 `openConversationId` 和任务结果;只对查询结果真实返回的字段执行读回验证。
- 写接口成功但现有查询未返回目标设置时,报告真实写入回执和不可独立读回的边界;不用群名、
成员数等其他字段代替验证,也不猜未发布的读回命令。
- 任一自然目标零命中或多候选时,在写入前整体停止。
- 逐项写入保留 succeeded/failed/unknown ledger,不用重试抹掉失败项。
- 分享邀请时 `--target``--receiver` 只能二选一;接收对象不明确时先确认。
- 机器人进群失败时确认机器人身份和当前用户管理权限,不连续切换同义原子命令。
@@ -0,0 +1,121 @@
# group-discovery:群发现、列表与成员读取
> 返回入口:[DingTalk Chat Skill](../../SKILL.md)
用于只读的群列表、群搜索、共同群、群成员、群机器人和邀请链接。建群、改群、成员增删、
邀请卡片分享、公告、禁言和其他群管理写操作读取 [group-admin.md](group-admin.md)。
## 入口选择
| 用户终点 | 唯一推荐入口 |
|---|---|
| 我加入的全部群 | `dws chat +my-groups --page-all` |
| 我创建或管理的群 | `dws chat +chat-list-mine` |
| 只看群主群或管理员群 | `+chat-list-mine --role OWNER|ADMIN` |
| 按关键词搜索群 | `dws chat +chat-search --query <关键词>` |
| 查看指定群全部成员 | `dws chat +chat-members-list --group <群名或ID>` |
| 已知成员 openDingTalkId 批量查群内详情 | `dws chat +chat-members-get --id <cid> --users <ids>` |
| 获取群邀请链接 | `dws chat +chat-invite-url --group <群名或ID>` |
| 查看群机器人 | `dws chat +chat-bots --group <群名或ID>` |
“全部群”与“全部会话”不同:`+my-groups` 只列当前用户加入的群;
`+conversation-list --page-all` 可能同时包含单聊和群聊,不能替代群成员关系。
## 群列表、分页与角色
`+my-groups` 返回当前用户加入的群,包括作为群主、管理员和普通成员加入的群:
- 要求完整列表时使用 `--page-all`Runtime 沿真实 `nextCursor` 读取后续页,并按
`openConversationId` 合并去重,读完后再应用可选 `--type` 本地过滤。
- `--limit` 是每页数量,不是最终结果上限;`--cursor` 只用于从已有 `nextCursor` 手工续读。
- `--page-limit` 只与 `--page-all` 一起使用,用于限制最多读取页数。达到上限后仍有下一页时,
结果不完整。
- 只有 `complete=true``hasMore=false` 才能声称已经读取全部;否则保留 `nextCursor`
`stopReason``failures` 并说明结果不完整。
```bash
dws chat +my-groups --page-all --page-limit 50 --format json
```
`+chat-list-mine` 只返回当前用户作为群主或管理员的群。只要群集合时不传 `--role`
一次取得 OWNER 和 ADMIN。要求逐项标明身份时,直接分别查询 `--role OWNER`
`--role ADMIN`,不先执行无角色查询或读取 Help;按 `openConversationId` 合并去重后,
再应用一次全局数量上限,不得把两个分支直接拼接。
```bash
dws chat +chat-list-mine --limit 20 --format json
dws chat +chat-list-mine --role OWNER --format json
dws chat +chat-list-mine --role ADMIN --exclude-muted --format json
```
`+my-groups` 不提供当前用户角色。用户明确要求普通成员群时,使用
`chat group list-all --limit 200`;返回 `hasMore=true` 时,必须把真实 `nextCursor`
传给下一次调用并继续读取,直到 `hasMore=false`,不得把继续翻页交给用户。读完后按
`openConversationId` 去重,仅筛选真实返回的 `myRole=普通成员`;不得给 `+my-groups`
编造 `--role MEMBER`,也不得用“全部群减去 OWNER/ADMIN 群”推断。
## 群搜索与稳定 ID
群搜索默认使用 `+chat-search`。要求全部候选时加 `--page-all`;可用
`--page-size/--page-token` 或兼容 `--limit/--cursor`。零命中或多候选时停止并展示候选,
不要选择第一项。
```bash
dws chat +chat-search --query "项目冲刺" --page-all --format json
```
只有数字群号时,使用 `chat group get-by-group-id --group-id <数字>` 转换为
`openConversationId`。需要搜索共同群时使用原子 `chat search-common``AND` 表示所有人
都在群里,`OR` 表示任一人在群里。自然人员必须先解析为当前 profile 的真实身份。
```bash
dws chat search-common --nicks "测试用户甲,测试用户乙" --match-mode AND --limit 20 --cursor 0
```
## 群成员
`+chat-members-list` 接受群名或 `openConversationId`,唯一解析后全量读取,并把用户与机器人
分桶。结果必须检查 `buckets/complete/failures`
```bash
dws chat +chat-members-list --group "项目群" --format json
dws chat +chat-members-list --conversation-id <openConversationId> --format json
```
先检查 `+chat-members-list` 的稳定结果。只有结果未包含用户要求的群昵称、角色或其他群内字段时,
才使用其中的真实 `openDingTalkId` 批量调用:
```bash
dws chat +chat-members-get --id <openConversationId> \
--users <openDingTalkId1>,<openDingTalkId2> --format json
```
不要为了群内详情默认切换到企业通讯录;只有用户明确要求部门、岗位、直属主管等企业资料时,
才把真实 userId 交给 `dingtalk-contact`
## 邀请链接与机器人
`+chat-invite-url` 是只读获取链接,可选 `--expires-seconds``group share-invite` 会实际把
邀请卡片发送给另一个会话或用户,属于 [group-admin.md](group-admin.md)。
`+chat-bots` 返回稳定 `bots[]``openBotId`,供后续移除。搜索可用机器人、机器人发送和
撤回读取 [chat-bot.md](chat-bot.md)。
## 原子 fallback
| 原子命令 | 仅用于 |
|---|---|
| `chat search` / `search-common` | Shortcut 未发布的搜索字段或共同群 |
| `chat group get-by-group-id` | 数字群号转换 |
| `chat group members` | 需要原始成员分页响应 |
| `chat group members list-by-ids` | 需要原始批量成员详情 |
| `chat group list-all` / `list-my-groups` | 需要 Shortcut 未投影的真实底层字段 |
使用原子 fallback 前读取精确 leaf Schema;不得把 fallback 写成与 Shortcut 并列的默认路线。
## 完成与错误
- 分页完成只以真实 `complete/hasMore/nextCursor/failures` 判断,不看过滤后的 `count` 猜测。
- 所有稳定 ID 必须来自同一 profile 的真实返回。
- 找不到群或出现多候选时停止,不臆测 `openConversationId`
- 任务从只读发现转为写操作时,使用 [group-admin.md](group-admin.md) 的目标和安全规则。
@@ -0,0 +1,132 @@
# message-actions:消息编辑、撤回、回复与对象操作
> 返回入口:[DingTalk Chat Skill](../../SKILL.md)
用于对真实消息执行编辑、撤回、引用回复、转发、Pin、Top、Favorite 和表情回应写操作,
并包含必要的紧邻验证。需要跨多个阶段传递真实结果的组合流程由
[01-messaging.md](../01-messaging.md) 说明;本文件不重复完整工作流。
## 入口选择
| 用户终点 | 推荐入口 |
|---|---|
| 撤回当前用户消息 | `dws chat +messages-recall --msg-id <openMessageId>` |
| <!-- dws-intent: chat.reply.quote -->引用回复 | `dws chat +messages-reply` |
| 编辑已发送消息 | `dws chat message edit` |
| 单条/合并/话题转发 | `+messages-forward` / `+messages-combine-forward` / `+messages-forward-topic` |
| Pin / Unpin | `+messages-set-pin` / `+messages-unset-pin` |
| 消息 Top / 取消 Top | `+messages-set-top` / `+messages-unset-top` |
| Favorite / 取消 Favorite | `+flag-create` / `+flag-cancel` |
| 默认 emoji 回应 | `+messages-add-emoji` / `+messages-remove-emoji` |
所有写操作以最终 Runtime gate 和精确 leaf Schema 为准。确认对象、消息和影响后再执行;
不要因为文档示例自行制造或省略 confirmation。
## 稳定 ID 规则
- `openTaskId` 是发送任务 ID,不是消息 ID。
- 撤回、编辑、回复、转发、Pin、Top 和 reaction 使用真实查询结果中的 `messageId`
- 同时保留消息的 `conversationId`、thread、发送者和引用上下文。
- 子消息使用自己的 `messageId`;只在缺会话 ID 时继承父消息 `conversationId`
- Bot 撤回使用 `processQueryKey`,不使用本文件的 `openMessageId` 路线。
刚由用户身份发送的消息如果只得到 `openTaskId`,先查询发送状态:
```text
+messages-send 或 message send
→ openTaskId
→ message query-send-status
→ openMessageId + openConversationId
→ 编辑或撤回
```
## 撤回与编辑
`+messages-recall` 可只传 `--msg-id`;省略会话 ID 时 CLI 会通过只读消息详情补齐。
兼容单值 `--message-ids`,但不要把 `processQueryKey` 当消息 ID。
```bash
dws chat +messages-recall --msg-id <openMessageId> --format json
dws chat +messages-recall --conversation-id <openConversationId> --msg-id <openMessageId> --format json
```
编辑使用 `message edit --conversation-id <cid> --msg-id <id>`,并在 `--text``--content`
中二选一。`--text` 由 CLI 生成 Markdown content`--content` 必须是完整 content JSON。
```bash
dws chat message edit --conversation-id <openConversationId> --msg-id <openMessageId> --text "更新后的内容"
dws chat message edit --conversation-id <openConversationId> --msg-id <openMessageId> --content '{"title":"标题","text":"更新后的内容"}'
```
群聊 @所有人使用 `--at-all`;指定人员使用 `--at-open-dingtalk-ids`。正文中的占位符以
Runtime 规范化结果为准,不把裸展示名当稳定身份。
## 引用回复与转发
引用回复默认使用 `+messages-reply``--group` 和消息 ID 来自真实查询;
`--ref-sender` 可省略时让 CLI 只读补齐,不手工猜发送者身份。
```bash
dws chat +messages-reply --group <openConversationId> \
--message-id <openMessageId> --content "收到" --format json
```
| 动作 | 入口 | 关键上下文 |
|---|---|---|
| 单条转发 | `+messages-forward` | 源消息 ID、源会话、目标会话 |
| 合并转发 | `+messages-combine-forward` | 多个真实消息 ID、源/目标会话 |
| 话题转发 | `+messages-forward-topic` | 源消息、源会话、源 thread、目标会话 |
只有 Shortcut 尚未发布真实必需字段时,才评估原子 `message reply``forward`
`combine-forward``forward-topic`,并先读取精确 leaf Schema。不要复制正文伪装原生转发。
## Pin、Top 与 Favorite
| 对象 | 写入入口 | 说明 |
|---|---|---|
| 消息 Pin | `+messages-set-pin` / `+messages-unset-pin` | 作用于一条消息 |
| 消息 Top | `+messages-set-top` / `+messages-unset-top` | 作用于会话内一条消息 |
| Favorite | `+flag-create` / `+flag-cancel` | 当前用户收藏 |
| 会话 Top | `+conversation-set-top` | 作用于整个会话,不属于本文件 |
用户要求确认 Pin 已生效时,使用 `+messages-list-pin` 检查真实结果中的 `messageId`;取消 Pin
后仅在用户要求确认取消结果时再次查询。典型短链为:`+messages-set-pin`
`+messages-list-pin``+messages-unset-pin`
需要原子 fallback 时,消息 Pin 对应 `message set-pin-msg/unset-pin-msg`,消息 Top 对应
`message set-top-msg/unset-top-msg`Favorite 对应 `message add-favorite/remove-favorite`
四种对象不能互换,即使用户都使用“收藏、钉住、置顶”等自然语言。
## 表情回应
优先在 [chat-emoji-list.md](../chat-emoji-list.md) 按表情名称查默认 emoji,不必全文理解表格。
| 场景 | 入口 |
|---|---|
| 添加/移除默认 emoji | `+messages-add-emoji` / `+messages-remove-emoji` |
| 默认表情无合适项时创建文字表情 | `+messages-create-text-emotion` |
| 添加/移除文字表情 | `+messages-add-text-emotion` / `+messages-remove-text-emotion` |
| 替换文字表情 | `message update-text-emotion` |
reaction 查询属于 [message-query.md](message-query.md),不要为了查看回应执行写命令。
## 流式卡片与文本工具
流式卡片使用根 Skill 直接链接的 [card/create.md](../card/create.md)、
[card/update.md](../card/update.md) 和 [card/schema.md](../card/schema.md);本文件不复制卡片参数。
纯文本翻译使用:
```bash
dws chat text translate --query "你好世界" --to en_US
```
用户只要求翻译文本时不要误走消息发送。
## 完成与错误
- 写操作检查任务级结果、投递状态和失败项,不只看退出码。
- 投递状态 unknown 时保留幂等键,不自动换目标重发。
- `unknown flag` 时读取精确 leaf Help,最多修正一次。
- 目标消息不存在、会话不匹配或发送者上下文缺失时停止,不猜 ID。
- 已知稳定消息 ID 的单一动作及其紧邻验证均在本文件完成。
@@ -0,0 +1,76 @@
# message-media:特殊消息与资源下载
> 返回入口:[DingTalk Chat Skill](../../SKILL.md)
只用于位置、联系人名片、底层 mediaId/fileId 和消息资源下载。普通文本、Markdown、文件、
图片、音频和视频发送继续按根 Skill 使用 `+dm``+send-to-group``+messages-send --file`
不读取本文件。
## 默认边界
- 用户身份普通文件/音视频:`dws chat +messages-send --as user --file <相对路径>`
- 已知资源引用单独下载:`dws chat +messages-resource-download`
- 从消息中定位并下载资源:在定位消息的 `+chat-messages``+search-msg`
`+messages-mget` 同一次调用中加 `--download-resources`
- 只有 Shortcut 尚未发布的位置、联系人名片或真实底层媒体字段,才使用原子 fallback。
<!-- dws-intent: chat.send.advanced -->`dws chat +messages-send` 的 user 文件能力不能外推给 Bot/Webhook
机器人富媒体边界读取 [chat-bot.md](chat-bot.md),不得静默改成当前用户身份。
## 位置与联系人名片
位置消息必须确认纬度、经度、地址名称和地图缩略图 mediaId:
```bash
dws chat message send --conversation-id <openConversationId> --msg-type location \
--latitude <纬度> --longitude <经度> --location-name <地址名称> \
--map-thumbnail-url "@mediaId"
```
联系人名片的 `--contact-id` 必须是联系人 `openDingTalkId`,不能把 userId 直接代入:
```bash
dws chat message send --conversation-id <openConversationId> \
--msg-type profile --contact-id <openDingTalkId>
```
用户要求真实发送结果时,保留发送返回的 `openTaskId`,再执行:
```bash
dws chat message query-send-status --open-task-id <openTaskId> --format json
```
检查真实 `sendStatus``openMessageId``openConversationId`
原子 `message send` 只在 Shortcut 缺少真实必需字段时使用。群聊目标用 `--conversation-id`;单聊目标
`--user``--open-dingtalk-id`,三者通常互斥。发送前核对接收对象、消息类型和资源来源。
## 资源下载
公开 `+messages-resource-download` 使用工作目录内安全相对路径,默认不覆盖;完整文件先写入
临时落盘再原子发布。覆盖必须由用户显式传 `--overwrite`,读取和下载不需要 `--yes`
任务要求从某条消息中定位并下载资源时,优先在限定会话、消息或时间范围的查询中加
`--download-resources --output-dir <目录>`,并检查下载 ledger。`+messages-resource-download`
只用于已经持有完整、真实且属于当前组织/profile 的独立资源引用、无需再定位消息的场景。
`fileId` 返回 `RESOURCE_NOT_FOUND`,不得把同一个 ID 改称 `mediaId` 重试,也不得原样
重复调用;应回到消息查询并使用 `--download-resources`
底层 fallback
```bash
dws chat message download-media --type mediaId --resource-id <mediaId> \
--message-id <openMessageId> --open-conversation-id <openConversationId> \
--output ./downloads/
```
`resource-id``message-id` 和会话 ID 必须来自同一 profile 下的真实消息查询结果。
当前没有 Range/断点续传;失败时保留 ledger 或错误,显式重试整个文件,不拼接残片。
## 完成与错误
- 查询并下载时同时检查消息完整性和每项下载 ledger;单项失败不抹掉已取得消息。
- 文件/音视频发送失败先确认工作目录内相对路径可读,不恢复独立上传再提取 mediaId 的旧默认链路。
- 位置参数不完整时先向用户确认,不猜经纬度或缩略图。
- 名片发送失败时确认 `--contact-id` 是 openDingTalkId。
- 下载目标存在时默认停止;只有用户明确允许覆盖时才传 `--overwrite`
@@ -0,0 +1,135 @@
# message-query:消息读取、搜索与查询
> 返回入口:[DingTalk Chat Skill](../../SKILL.md)
用于浏览或导出指定会话、按条件搜索消息、按消息 ID 读取详情、查看 @我、话题回复、
Favorite、Pin 和 reaction。只读任务优先使用 Shortcut;只有 Shortcut 未发布所需底层字段、
原始响应或手工 continuation 时才读取精确原子 leaf Schema。
## 入口选择
| 用户终点 | 唯一推荐入口 |
|---|---|
| <!-- dws-intent: chat.read.conversation -->浏览或导出一个指定群聊/单聊 | `dws chat +chat-messages` |
| <!-- dws-intent: chat.search.filtered -->发送者、关键词、@对象或消息类型是主要条件 | `dws chat +search-msg` |
| 已知消息 IDs 读取详情 | `dws chat +messages-mget` |
| 查看 @我的消息 | `dws chat +at-me` |
| 查看 Favorite | `dws chat +flag-list` |
| 已知话题主消息或 thread/topic ID 读取回复 | `dws chat +thread-replies` |
`+chat-messages` 是指定会话的粗粒度读取;`+search-msg` 是目标条件明确的单/跨会话检索。
不要先读完整会话再补跑搜索,也不要把群名或姓名直接填入只接受稳定 ID 的参数。
## 指定会话读取
群聊 `--group` 可传群名或 `openConversationId`;也可用 `--chat-query` 显式解析群名、
`--conversation-id` 显式传稳定 ID。单聊使用 `--user``--open-dingtalk-id`
```bash
dws chat +chat-messages --group <群名或openConversationId> --format json
dws chat +chat-messages --group <openConversationId> --page-all --page-limit 50 --format json
```
可附带非必填的 `--sender-query <姓名>`:未传时返回全部消息;唯一解析出
userId/openDingTalkId 后,按消息 `senderId` 筛选同一次读取结果,覆盖最终
`messages/count` 并返回 `resolvedFilters`。解析失败、不完整或存在歧义时抑制未过滤消息,
返回 `sender_resolution_failed`,不得把全量消息当作发送者筛选结果。
`--sender` 是姓名、userId 或 openDingTalkId 的混合入口。通讯录无法确认输入类型时,可按
原值 userId 精确过滤并交付命中消息,但结果必须保留 `identity_unverified`,不得把字符串命中
升级为已验证身份,也不得据此作完整否定结论。
```bash
dws chat +chat-messages --group "项目群" --sender-query "测试用户甲" --page-all --format json
```
时间范围使用公开可选的 `--start``--end``--order asc|desc`,兼容别名为
`--start-time/--end-time/--sort`。范围为 `[start,end)`;仅开始时间表示到本次执行当前时间;
仅结束时间只支持 `desc``asc` 必须提供开始时间。旧 `--time/--direction` 只用于兼容的
单边界模式,不能与范围模式混用。
```bash
dws chat +chat-messages --group <openConversationId> \
--start "2026-08-01T00:00:00+08:00" --end "2026-08-02T00:00:00+08:00" \
--order asc --page-all --format json
```
完整读取后只需消息字段可判断的子集时,在同一次调用中使用全局 `--jq`,保留根信封并
同步改写 `messages/count`;不得丢失 `complete``hasMore``failures` 等 ledger。
发送者姓名仍使用 `--sender-query` 解析稳定身份,不用 `--jq` 比较展示名。
```bash
dws chat +chat-messages --group "项目群" --page-all --format json \
--jq '. as $root | [.messages[] | select((.reactions // []) | length > 0)] as $matched | $root | .messages = $matched | .count = ($matched | length)'
```
要求导出时用 `--output <工作目录内相对.json>` 原子写入;需要资源时在读取命令上加
`--download-resources`,不要让 Agent 先输出全量 JSON 再手工遍历资源引用。
## 多维度搜索
- 关键词使用公开 `--query`
- 已知稳定会话 ID 使用 `--group` / `--groups`;稳定发送者 ID 使用 `--senders`
- 只有群名时使用 `--chat-query`,由 CLI 唯一解析会话。
- 只有发送者姓名时使用 `--sender-query`,由 CLI 唯一解析人员。
- 不传会话过滤时搜索全部会话;默认时间范围为最近 7 天。
- `--page-all` 只翻完当前时间范围内的游标页;精确范围使用成对的 `--start/--end`
- `--order` 只稳定排列已经取得的结果;未全量或 `complete=false` 时不得称为完整范围全局排序。
```bash
dws chat +search-msg --chat-query "项目群" --sender-query "测试用户甲" --page-all --format json
dws chat +search-msg --chat-query "项目群" --query "发布计划" --page-all --format json
dws chat +search-msg --sender-query "测试用户甲" --page-all --format json
```
需要 Shortcut 未发布的原始过滤字段或响应时,才评估 `message search-advanced`。它支持
发送者、@对象、多个会话、消息类型、会话类型、机器人消息和时间范围,但不是默认入口。
至少提供一种真实过滤条件,完整遍历只有 `--page-all` 会触发。
## 其他查询
### 已知消息、@我与话题回复
- `+messages-mget --msg-ids <id...>`:最多 50 条;结果可直接用于回复、转发、撤回和资源下载。
- `+at-me [--group <群名或ID>] --page-all`:群内或跨全部会话查看 @我的消息
- `+thread-replies --message-id <rootMessageId>`:自动只读解析 conversation/thread。
- `+thread-replies --group <cid> --thread-id <threadId>`:显式稳定上下文。
话题回复默认 `desc``asc` 必须与 `--page-all` 一起使用。自动续页使用下层毫秒级
`nextCursor`,不得使用只有秒精度的展示时间手工拼 continuation。检查 `complete`
`hasMore``stopReason``failures`
### Favorite、Pin 与 reaction 查询
| 任务 | 入口 |
|---|---|
| Favorite 列表 | `+flag-list`;要求全部时加 `--page-all`,页大小 130 |
| 消息 Pin 列表 | `message list-pin-msg --open-conversation-id <cid>` |
| 批量 reaction/文字回应 | `message list-emotion-replies --msg-ids <id...>` |
| 已读/未读状态 | `message read-status --group <cid> --message-id <id>` |
Favorite、消息 Pin、消息 Top 和会话 Top 是不同对象。写入或取消这些状态读取
[message-actions.md](message-actions.md),这里只负责查询。
## 原子 fallback
| 原子命令 | 仅用于 |
|---|---|
| `message list` | 指定会话原始响应或显式手工 continuation |
| `message list-all` | 时间范围内全部会话的原始分页响应 |
| `message list-by-sender` | 已有稳定发送者 ID 且需要底层原始响应 |
| `message list-mentions` / `list-focused` | @我或特别关注的原始列表 |
| `message search` / `search-advanced` | Shortcut 未发布的真实过滤字段 |
| `message list-by-ids` | 已知消息 ID 的原始详情响应 |
Typed `chat message` 自动翻页只由 `--page-all` 触发;只传 `--page-limit``--max-items`
`--page-delay` 仍是单页。非第一页失败时保留 partial 结果、失败页和 continuation,不能
把 partial result 表述成完整成功。
## 完成与错误
- 查询必须检查 `complete``hasMore``stopReason``failures` 和下载 ledger。
- 发送者/群名零命中或多候选时停止,不选择第一项。
- `unknown flag` 时读取精确 leaf Help,修正后最多重试一次。
- 子消息优先使用自己的 `messageId`;只在缺会话 ID 时继承父消息的 `conversationId`
- 查到真实消息后需要写操作时,使用 [message-actions.md](message-actions.md) 中的稳定 ID 规则。
@@ -0,0 +1,43 @@
# 话题与话题圈
> 返回入口:[DingTalk Chat Skill](../../SKILL.md)
话题(Thread)是一条主消息及其回复线,可以位于普通群或话题圈中,使用 `openConvThreadId` 标识;承载话题的父群使用 `openConversationId`。命令沿用拆分前 `chat group` / `chat message` 的参数名称。只有需要新建话题圈时才使用 `create-group`,已有群中的话题可直接使用其余 `chat thread` 命令。
## 入口选择
| 用户终点 | 推荐入口 |
|---|---|
| 已有稳定成员 ID 创建话题圈 | `dws chat thread create-group --name <名称> --users <userId,...>` |
| 发布新话题 | `dws chat thread send --conversation-id <openConversationId>` |
| 浏览话题主消息 | `dws chat thread list --conversation-id <openConversationId>` |
| 向具体话题直接追加回复 | `dws chat thread reply --conversation-id <openConvThreadId>` |
| 分页读取一个话题的回复 | `dws chat thread list-replies --conversation-id <openConversationId> --topic-id <openConvThreadId>` |
| 转发整条话题 | `dws chat thread forward --src-msg-id <openMessageId> --src-conversation-id <openConversationId> --src-thread-id <openConvThreadId> --dest-conversation-id <openConversationId>` |
| 撤回话题中的一条消息 | `dws chat thread recall-message --conversation-id <openConversationId> --message-id <openMessageId>` |
| 添加或移除 emoji | `dws chat thread add-emoji` / `remove-emoji` |
| 查询 Thread 消息的表情回复 | `dws chat thread list-emotion-replies --msg-ids <openMessageId,...>` |
| 添加、移除或更新文字表情 | `dws chat thread add-text-emotion` / `remove-text-emotion` / `update-text-emotion` |
## 发布、回复与读取
`thread send``--conversation-id` 是承载话题的会话 `openConversationId`,用于发布新的顶层话题。
`thread reply` 沿用原发送命令的 `--conversation-id`,但这里传 Thread 子会话的 `openConvThreadId`。它直接追加回复,不使用消息引用回复,也不创建新的顶层 Thread。
已有父会话 `openConversationId` 和 Thread `openConvThreadId` 且只需读取一页时,使用 `thread list-replies --conversation-id ... --topic-id ...`。需要按主消息自动解析、全量翻页、排序或下载资源时,使用 `+thread-replies` Shortcut。
用户需要逐条查看、列出或概括具体回复内容时,使用 `thread list-replies`;只浏览话题主消息时使用 `thread list`。需要自动读取全部页面、排序或下载资源时,使用 `+thread-replies` Shortcut。
整条 Thread 可转发到普通群;当前不支持从话题圈向另一个话题圈转发整条 Thread。
## 消息操作
撤回、emoji 和文字表情命令沿用对应 `chat message` 命令的主参数。Runtime 会先读取消息并校验其属于 Thread,再执行操作;批量查询会逐条校验 `--msg-ids`。文字表情的 `emotionId``backgroundId`、名称和文字使用 `chat message create-text-emotion` 返回的实际值;移除时使用已添加的值,更新时用 `--old-emotion-id` 传当前值、其余表情参数传新值。
## 完成与错误
- 创建话题圈返回真实群会话结果,不额外制造 `openTopicId` 字段。
- 发布和回复沿用异步发送结果;`openTaskId` 是任务 ID,后续消息操作需要从发送状态或消息查询中取得真实消息 ID。
- Thread 主消息和回复均保留 `openConvThreadId`,父容器继续使用 `openConversationId`
- 标识缺失、类型不明或消息不属于 Thread 时停止,不猜 ID。