# IM 稳定契约与能力边界 本页只记录需要跨命令复用的 Runtime 契约。下面四个 marker 区块由 `check-multi-im-skill-chain.sh` 对照 Go typed descriptor 逐字校验;修改能力时先改 Runtime、 测试与 descriptor,再同步本页。命令参数仍以精确 leaf Schema 为准。 ## 消息结果 `im.message-list.v1` `+chat-messages`、`+search-msg`、`+messages-mget` 及相关消息读取使用同一兼容版本。 字段可能为空,但不能换名猜测;全量任务必须结合完整性 ledger 判断。 - `version`: `im.message-list.v1` - `message_fields`: `messageId`, `conversationId`, `threadId`, `sender`, `senderId`, `senderType`, `messageType`, `text`, `createTime`, `updateTime`, `reactions`, `quotedMessage`, `forwarded`, `resourceRefs` - `envelope_fields`: `contractVersion`, `messages`, `count`, `resolvedFilters`, `queryRange`, `pagesFetched`, `paginationKnown`, `complete`, `hasMore`, `nextPage`, `stopReason`, `truncated`, `truncatedByPageLimit`, `truncatedByResultLimit`, `failedCount`, `failures`, `partial`, `scope`, `resourceDownloads` 当 `complete=false` 时不能称为全量成功。`nextPage` 只能来自真实 lower boundary; `failedCount/failures`、`partial`、总 `truncated` 和两个原因字段必须原样保留。 当 Runtime 解析并应用自然发送者条件时,`resolvedFilters.senders[]` 保留原查询及选中的 `userId/openDingTalkId`。消息展示名可以与通讯录姓名不同;只能用稳定 `senderId` 与解析结果关联, 不得重新做姓名字符串比较。 当查询声明时间范围或顺序时,`queryRange` 保留规范化的 `startTime`、`endTime`、`order` 与 `semantics=[start,end)`。排序只覆盖本次实际取得的 `messages`;`complete=false` 时不得把它描述为完整范围的全局排序。 ## `+messages-send` 身份矩阵 | identity | targets | content types | natural targets | mention targets | idempotency keys | batch ledger | |---|---|---|---|---|---:|---:| | `user` | `group`
`direct-user`
`direct-open-dingtalk-id` | `text`
`markdown`
`image-media-id`
`file`
`audio-as-file`
`video-as-file` | `chat-query`
`user-query` | `open-dingtalk-id`
`all` | `true` | `false` | | `bot` | `group`
`groups`
`direct-users`
`direct-open-dingtalk-ids` | `text`
`markdown` | — | `user-id`
`open-dingtalk-id`
`all` | `false` | `true` | | `webhook` | `token-owned-group` | `text`
`markdown` | — | `user-id`
`mobile`
`all` | `false` | `false` | Bot 多群用 `--groups` 或 `--groups-file`,Runtime 去重后输出 `im.batch-write.v1` 逐目标 ledger。Bot/Webhook 不支持的内容类型会在写前失败,不能降级为 另一身份或偷偷改成纯文本。 ## 流式卡片 - `version`: `im.streaming-card.v1` - `targets`: `group`, `direct-user`, `direct-open-dingtalk-id` - `content_types`: `streaming-text` - `flow_statuses`: `1=processing`, `2=typing`, `3=completed`, `4=executing`, `5=error` - `callback_supported`: `false` 发送目标与状态范围由 Runtime 校验。当前不是 Lark Card JSON 编译器,也不消费按钮 callback; 具体创建和更新流程见 `card/` 下的精确 reference。 ## 正向能力与负向边界 | capability | supported | current route / boundary | |---|---:|---| | `thread-write` | `false` | quote reply with +messages-reply; thread reading with +thread-replies | | `bot-rich-media` | `false` | bot text/markdown, or current-user file/image send | | `card-action-callback` | `false` | streaming text card create/update only | | `resource-resume` | `false` | atomic whole-file download with explicit retry | | `group-member-full-pagination` | `true` | +chat-members-list or +group-members | | `group-owner-selection` | `true` | +chat-create owner flags | `supported=false` 是执行门禁,不是待猜测字段。只有 lower interface、Runtime、测试、Schema 和 此页同时升级后,才能改变对外承诺。 话题圈会话仍禁止引用消息回复;向 Thread 追加回复使用 `chat thread reply --conversation-id `。