# OneTalk 引用回复:Mind 对接说明 > 适用范围:Mind 已接入 Bright OneTalk WebSocket 的文本发送链路。本说明只增加引用目标字段,不改变连接、授权、普通发送或发送结果协议。 ## 1. 能力与边界 Mind 在 OneTalk 时间线中选择一条**文本消息**后,可以发送一条引用该消息的新文本。Mind 只向 Bright 提交被引用消息的 OneTalk `messageId`;Bright 和插件负责在同一账号、同一会话内解析 OneTalk SDK 所需的原始引用对象。 Mind 不得发送、保存或展示下列数据: - OneTalk SDK `referMessage` / `originalData`; - `.PNM` 后缀的 SDK 传输别名; - 根据正文、时间、发送人或 UI 序号推导出的 ID; - Mind 数据库 UUID(它不是 OneTalk `messageId`)。 第一版只支持“引用文本后发送文本”。图片和文件仍走既有普通发送,不能附带引用字段。 ## 2. 引用目标的来源 从 Bright 返回的 OneTalk 时间线消息中读取该条消息的 `id` / `messageId`,将其原样作为 `replyToMessageId`。 ```ts type ReplyTarget = { messageId: string; // Bright OneTalk messageId,不是 Mind UUID from: string; text: string; }; ``` 仅当时间线行满足以下条件时显示“回复”入口: - 消息正文是非空文本; - `messageId` 为非空字符串; - 消息属于当前 OneTalk 会话,且不是 system、optimistic 或本地临时消息。 `messageId` 不做 trim、拼接或格式转换;例如 `123456.PNM` 不是合法的 `replyToMessageId`。 ## 3. 发送帧增量 沿用既有 `send.request` WebSocket 帧。在当前共享协议版本 **9** 中,引用发送的 payload 必须恰好为以下形状: ```json { "conversationId": "c123", "content": { "kind": "text", "text": "这条消息是在回复前文" }, "replyToMessageId": "123456" } ``` 完整帧示例(`scope`、`requestId` 与 `sendRequestId` 继续使用当前 Mind 的既有生成与关联逻辑): ```json { "protocolVersion": 9, "connectionType": "mind_page", "type": "send.request", "requestId": "mind-frame-001", "sendRequestId": "mind-send-001", "scope": { "workspaceId": "workspace-1", "mindUserId": "mind-user-1", "channelAccountId": "286995452" }, "payload": { "conversationId": "c123", "content": { "kind": "text", "text": "这条消息是在回复前文" }, "replyToMessageId": "123456" } } ``` 普通发送保持原样,**省略** `replyToMessageId`: ```json { "conversationId": "c123", "content": { "kind": "text", "text": "普通文本" } } ``` 不要把 `replyToMessageId` 放到 `content`、`ext` 或其他扩展对象中;协议采用严格字段校验,未知字段或错误层级会被拒绝。 ## 4. Mind 侧校验 发起引用发送前,Mind 必须确认: - `conversationId` 是当前会话的 OneTalk `conversationId`; - `replyToMessageId` 非空、没有首尾空白,且不是纯数字加 `.PNM`; - `content.kind === "text"` 且 `content.text` 非空; - 当前 WebSocket scope 中的 `channelAccountId` 与时间线消息所属账号一致。 不要在客户端把无效引用降级为普通文本发送。若本地无法确定目标 ID,应禁用发送并提示用户重新选择消息。 ## 5. Composer 交互 点击“回复”后,Mind 只保留临时 UI 状态 `{ messageId, from, text }`:composer 中显示发送者和截断文本摘要,并提供“取消引用”。 以下场景必须清除该临时状态: - 切换 OneTalk 会话; - 收到 `confirmed_sent`; - 收到 `rejected_before_send`。 收到 `delivery_unknown` 时,不能自动重试或伪造发送成功;应保留既有“结果未知”的可见状态,由用户决定后续操作。 第一版不要求 Mind 解析或重新绘制远端消息里的引用卡片。引用内容由 OneTalk 页面渲染,Mind 时间线仍按 Bright 已返回的规范化消息展示。 ## 6. 结果处理 `send.result` 与普通发送使用同一关联键 `sendRequestId`,结果语义不变: | status | Mind 行为 | | ---------------------- | --------------------------------------------------- | | `confirmed_sent` | 将返回的已发送消息并入时间线,清除引用临时状态。 | | `rejected_before_send` | 显示 `reason`,清除引用临时状态;不得改发普通文本。 | | `delivery_unknown` | 显示结果未知;不得自动重试、不得假定消息已发送。 | 常见拒绝原因包括 `invalid_request`(引用 ID 不合法、引用目标不在当前会话或不支持的内容类型)、`waiting_for_page`、`page_not_found`、`page_identity_mismatch` 与 `send_not_supported`。Mind 应直接展示已有的发送错误状态,不自行转换错误码。 ## 7. 联调验收 1. 加载 OneTalk 会话与文本消息,确认时间线行使用 Bright 返回的真实 `messageId`。 2. 选择一条文本消息,发送引用文本,检查发送帧只有顶层 `payload.replyToMessageId`。 3. 确认 `send.result` 与同一个 `sendRequestId` 关联,并仅在 `confirmed_sent` 时显示发送成功。 4. 验证切换会话、取消引用与 `rejected_before_send` 都会清除 composer 的引用状态。 5. 验证普通文本、图片和文件发送均不携带 `replyToMessageId`,原有行为不变。 ## 8. 兼容性 Mind、Bright 与 Chrome 插件必须使用兼容的 OneTalk 协议版本部署。当前源码的协议版本为 9;上线前以实际运行中的共享 contract 为准,不要让旧客户端向新协议帧附加未知字段。