87 KiB
PR #860 Multi IM 优化:合并后完整代码分析与跨场景复用报告
PR #860:DingTalk-Real-AI/dingtalk-workspace-cli#860
#860 当前标题:
feat(im): harden Multi IM and publish complete Chat Schema#860 当前状态:Open、可合并;核对时共 14 个提交、129 个变更文件,+69,391 / -13,045。
唯一分析范围:
main@6376f294dab0d0a7bd2f5904077aab89383684d1...codex/multi-im-optimization@33ceab6000d5f18eddbc1c0c97544233f5dd42d6。报告原则:只分析当前 PR #860 的合并后整体代码。提交来源和中间分支不再作为独立分析单元;所有规模、架构、文件、风险和复用结论均以当前 #860 的完整 diff 为准。
1. 核心优化思路
1.1 一句话结论
PR #860 的本质不是增加一批 IM 命令,而是把 Chat/Event 能力从“分散、可调用”升级为“意图可路由、目标可确定、执行有边界、输出有契约、风险可确认、能力可发现、文档与代码可持续校验”的完整产品链路。
整体优化链路可以概括为:
用户意图
-> Golden Route 唯一入口
-> Typed Resolver 确定目标
-> Identity / Capability Preflight
-> Bounded Runtime + Typed Confirmation
-> Versioned Result / Error Ledger
-> Authored Registry + Selection/Metadata
-> Generated Schema + Skill/Reference
-> Policy + Drift + Coverage Gates
1.2 核心方法总览
| 原有问题 | 核心优化方法 | PR #860 整体落地 | 可复用价值 |
|---|---|---|---|
| 同一意图有多条相似入口 | Golden Route:每个意图只推荐一个默认入口 | 统一发送、回复、读取、搜索、建群和监听入口,原始命令只作有理由的 fallback | 通讯录、文档等领域都可先按意图收敛入口 |
| 名称、ID、URL 等目标解析分散 | Typed Resolver:业务执行前先得到规范化目标 | 新增 targetresolver,全分页检索、精确匹配、歧义和不完整结果均 fail closed |
可扩展为 DirectoryResolver、DocumentTargetResolver |
| 调用前才发现参数、身份或能力不支持 | Local Validation + Capability Check | 建立 user/bot/webhook 能力矩阵,并前置校验时间、页大小、回溯窗口和目标互斥 | 适用于邀请、删除、文档覆盖、权限修改等写操作 |
| 输出依赖原始 API 或展示文本 | Versioned Contract:输出稳定的机器契约 | 建立并发布 im.message-list.v1,统一消息、引用、资源、reaction 和 continuation |
可定义联系人、文档、云盘的 v1 投影 |
| 分页、导出、下载可能截断或留下半成品 | Bounded Execution:限制页数、条数、超时并支持原子提交 | 实现游标停滞检测、完整性账本、安全下载、no-clobber 和跨平台原子替换 | 适用于批量导出、备份、迁移和同步 |
| 高风险命令示例可能绕过确认 | Typed Confirmation:Runtime 强制停下,确认后才执行 | 写入/破坏型 Schema metadata 与 Runtime gate 对齐,危险示例不预填 --yes |
可用于删除联系人、覆盖文档、权限变更等高风险动作 |
| 能力可运行但 Agent 不可发现 | Authored Registry + Generated Schema | Chat Shortcut 达到 97/97;完整 Catalog 为 26 products / 898 tools | 适用于任何具有大量组合命令的产品域 |
| 文档、Schema、Runtime 各自演化 | Consistency Gates:把一致性变成 CI 规则 | 增加 Skill Chain、Schema compatibility、interface integrity、generated drift 和 changed-code coverage | 可抽象为所有领域共用的质量框架 |
1.3 八个可复用的优化原则
原则一:从“API 优先”转为“意图优先”
先定义用户究竟要完成什么,再为每个意图选择唯一 Golden Route。底层 API、历史命令和兼容别名可以保留,但不应继续出现在默认发现路径中。这样能够显著减少 Agent 在多个相似工具之间随机选择的问题。
原则二:把目标解析变成独立基础设施
所有操作先经过统一 Resolver,将名称、ID、手机号、URL 等输入转换为类型明确的 canonical target。业务命令只消费解析结果,不再各自实现搜索、歧义处理或 ID 猜测。
原则三:把写操作拆成“计划”和“执行”
执行前明确目标、身份、能力、副作用和恢复方式。高风险操作只有在目标唯一且能力满足时才进入执行阶段。这种拆分既降低误操作风险,也让 dry-run、确认和审计更容易实现。
原则四:用版本化域模型隔离上游变化
列表、搜索、读取和写回执都投影到稳定的领域契约。调用方依赖 messageId、canonicalId、nextCursor 等规范字段,而不是供应商原始响应或终端展示文字。
原则五:所有长流程都必须有边界和恢复语义
分页、导出、下载、批量发送不能只保证 happy path;还要定义最大页数、最大条数、游标推进、临时文件、原子替换、checkpoint、部分失败和幂等重试。
原则六:让错误直接驱动下一步动作
错误需要区分未命中、歧义、身份不匹配、能力不足、权限不足、限流和服务端故障,并明确是否可重试以及建议动作。对 Agent 而言,错误是控制流的一部分,而非日志文本。
原则七:把知识一致性纳入工程门禁
Skill 负责路由,Reference 负责细节,Schema 负责机器发现,Runtime 负责真实行为,Policy 负责检查四者闭环。任何新增能力都应同步更新并由测试验证。
原则八:把“正式发布”定义为独立交付阶段
Runtime 中存在一个命令,不等于 Agent 已经能够正确使用它。能力还必须进入 authored Registry,具备 use/avoid hints、风险和确认 metadata,生成 Schema/Agent metadata,并退出临时 exclusion。PR #860 将这一原则具体化为 Chat 97/97、public Shortcut 265/265 和完整 Catalog 898 tools。
1.4 标准执行链路
用户自然语言意图
|
v
Golden Route:选择唯一推荐入口
|
v
Typed Resolver:解析用户、群、会话、消息等目标
|
v
Preflight Plan:固化 profile、身份、能力和副作用
|
v
Bounded Runtime:在分页、超时、数量和文件边界内执行
|
v
Versioned Result / Typed Error Ledger:返回可消费、可恢复结果
|
v
Authored Registry + Selection/Metadata:正式发布并指导选择
|
v
Generated Schema + Skill/Reference + Policy:持续防止契约漂移
1.5 复用时应迁移整条链路
不建议只复制某个 shortcut 或 Resolver。若新领域仍缺少稳定输出、错误分类和一致性门禁,局部复用很快会重新产生分散实现。通讯录、文档、云盘、知识库等场景应至少成组迁移以下能力:
意图清单 + Golden Route
-> 统一 Resolver
-> Plan / Capability Check
-> 有界 Runtime
-> 版本化结果与结构化错误
-> 分层文档、Schema 与 Policy
2. 分析范围与阅读导航
2.1 变更规模与边界
本报告只使用一个三点对比范围:6376f294...33ceab60。它表示 PR #860 当前 head 相对当前 PR base 的完整净变化:
| 指标 | 当前 PR #860 |
|---|---|
| 状态 | Open / mergeable |
| 提交数 | 14 |
| 变更文件 | 129 |
| 新增 / 删除 | +69,391 / -13,045 |
| 生产 Go 文件 | 38(+4,028 / -737) |
| Go 测试文件 | 30(+4,343 / -88) |
| Skill Markdown | 30(+1,166 / -1,577) |
| 主要生成 Schema 文件 | 6(+57,215 / -9,229) |
#860 变更横跨:
- Runtime:
internal/app、internal/shortcut、internal/helpers、internal/errors。 - 目标解析:新增
internal/shortcut/targetresolver。 - Schema:chat/event 的 catalog、agent metadata、hints、registry。
- Skill:mono、chat、event、shared 四类文档链路。
- Policy:新增 Multi IM Skill Chain 检查并扩展上下文预算检查。
- 测试:单元测试、契约测试、mock MCP smoke test、live audit 辅助脚本。
这种范围说明优化目标不是“让某几个命令能跑”,而是建立可持续扩展的产品契约。
69,391 行新增中,大量内容来自 Schema catalog 和 Agent metadata 等生成物,不能把总行数等同于手写业务逻辑。人工设计变更主要集中在:
- Chat Shortcut 的 authored CommandRegistry、selection hints 和风险 metadata;
- 本地参数校验、确认门禁、cursor 修复、shorthand 和跨平台路径;
- Schema 完整性、目标消歧、分页、原子文件及跨平台 changed-code 覆盖测试;
- Chat、Event、Shared 和 Mono 四层文档链路重构。
2.2 文档阅读导航
| 阅读目标 | 建议章节 |
|---|---|
| 快速掌握本次优化的方法论 | 第 1 章“核心优化思路” |
| 理解为什么需要改造 | 第 3 章“优化前的典型问题” |
| 理解 Skill、Runtime、Schema、Policy 如何协同 | 第 4 章“总体架构” |
| 查看具体代码机制 | 第 5 章“核心代码优化分析” |
| 查看文档组织变化 | 第 6~8 章 |
| 查看验证方法与质量门禁 | 第 9 章 |
| 复用到通讯录、文档、云盘和知识库 | 第 10~12 章 |
| 查看当前风险收口和整体结论 | 第 13~14 章 |
| 查看 Schema 发布、Runtime 收口和文件分类 | 第 15~18 章 |
| 查看 Go 生产代码和测试代码的专项总结 | 第 19 章 |
| 查看当前 #860 的整体价值与建议 | 第 20~21 章 |
2.3 结论类型说明
为避免把“PR 已实现内容”和“建议复用方案”混在一起,后文按以下方式理解:
- 本次落地:能够在该 PR 的代码、Schema 或文档变更中找到直接依据。
- 分析判断:根据多处变更归纳出的设计意图或工程影响。
- 复用建议:面向通讯录、文档等新领域给出的迁移设计,并非声称已在本 PR 中实现。
3. 优化前的典型问题
3.1 同一意图存在多条入口
发送消息、查看群消息、回复消息等意图可能分别出现在 shortcut、底层 OpenAPI 命令、脚本和多份教程中。模型或用户容易选中功能相似但约束不同的路径,导致参数漂移、行为差异和排障困难。
3.2 目标解析散落在业务命令中
用户可能输入 conversation ID、openConversationId、群名、用户 ID、手机号或自然语言名称。若每条命令各自解析,就会出现:
- 同一个名称在不同命令中命中不同对象;
- 多结果时有的命令报错、有的静默选第一个;
- ID 类型混用;
- profile、tenant 或身份上下文不一致;
- 新增一种目标类型时需要修改大量命令。
3.3 列表输出面向人而非机器
原始 API 数据结构大而不稳定,字段含义不统一,分页元信息可能丢失。Agent 需要猜测正文、发送者、消息 ID 和时间字段,后续回复、导出和审计难以可靠衔接。
3.4 长流程缺少完整性边界
消息列表、成员列表、导出、下载等操作天然包含分页或文件写入。如果没有最大页数、最大条数、下一页游标、临时文件和原子替换机制,容易发生无限翻页、半文件、重复结果或悄然截断。
3.5 文档与 Runtime 独立演化
命令已经变更但文档仍指向旧路径,或者 Skill 声称支持某个字段而 Runtime 没有对应输出。问题往往到真实 Agent 调用时才暴露。
4. 总体架构:四层协同
4.1 Skill 层:告诉 Agent 应该走哪条路
Skill 的职责不是罗列所有命令,而是完成意图路由、默认值选择、风险提示和按需加载 Reference。它应该短、稳定、偏决策,不应复制完整 API 手册。
4.2 Runtime 层:保证行为确定且可测试
Runtime 负责统一解析目标、执行能力校验、分页、结果投影、原子文件操作和结构化错误。即使调用者没有阅读文档,Runtime 也应保持安全边界。
4.3 Schema 层:提供机器可发现的真实能力
Schema catalog、agent metadata、selection hints 和 command registry 必须共同描述参数、枚举、返回值和入口选择。Schema 不是生成物附件,而是 Agent 运行时能力的一部分。
4.4 Policy 层:防止三层再次漂移
Policy 检查关键意图是否同时存在合法 Runtime 路由、Schema 暴露和文档说明,并控制 Skill 的上下文体积。它把系统设计转化为可持续执行的合并门槛。
5. 核心代码优化分析
本章按照“目标识别—路由决策—读取契约—长流程执行—错误与兼容治理”的顺序展开。各项机制之间不是孤立关系:Resolver 提供可靠目标,身份/能力矩阵选择执行路径,版本化投影稳定结果,分页与原子写保证完整性,错误和 profile 契约负责失败恢复与上下文一致性。
| 分析主题 | 主要代码区域 | 解决的问题 |
|---|---|---|
| Target Resolver | internal/shortcut/targetresolver |
统一名称、ID 和自然语言目标解析 |
| 身份与能力路由 | internal/shortcut/chat/*contract.go、unified_send.go |
在执行前选择合法发送身份和路径 |
| 消息投影 | chat_message.go、smart/chat_messages.go |
将异构响应转换为稳定消息模型 |
| 分页与导出 | conversation/message/group/export 相关实现 | 防止静默截断、无限翻页和半成品文件 |
| 事件监听 | internal/app/event_listen_im.go |
将 IM 事件封装为显式生命周期能力 |
| 错误与上下文 | internal/errors、failure classifier、profilectx |
提供可行动错误并防止跨 profile 漂移 |
| 兼容治理 | 参数别名、Schema metadata、selection hints | 保持旧调用可用,同时引导新调用走 Golden Route |
5.1 统一 Target Resolver
新增的 internal/shortcut/targetresolver/resolver.go 将目标识别从各业务命令抽离。Resolver 的价值在于把“输入是什么”与“接下来执行什么业务”分开。
统一解析应遵循如下优先级:
- 显式类型化 ID 优先,避免把合法 ID 当名称搜索。
- 显式 target kind 优先于启发式判断。
- 自然语言名称进入搜索,并保留候选集。
- 唯一命中才自动继续;多结果返回可选择候选。
- 未命中返回稳定错误码和建议动作。
- 解析结果携带 profile、tenant、来源和置信信息。
这样做带来三个直接收益:
- chat、send、history、members 等命令共享完全一致的目标语义;
- 新增手机号、邮箱、unionId 等输入方式时只扩展 Resolver;
- 解析阶段可以独立测试,不需要触发真实写操作。
向通讯录迁移
可建立 DirectoryResolver:
输入:姓名 / 手机号 / 邮箱 / userId / unionId / 部门名 / deptId
输出:TypedDirectoryTarget
kind: user | department
canonicalId
displayName
matchedBy
candidates
profileContext
删除、调岗、批量邀请等高风险动作只接受唯一、类型确定的解析结果。
向文档迁移
可建立 DocumentTargetResolver:
输入:URL / docId / workspaceId / spaceId / 标题 / 路径
输出:TypedDocumentTarget
product: doc | drive | wiki
resourceType
canonicalId
containerId
matchedBy
candidates
这可消除文档 URL、知识库节点 ID、云盘文件 ID 混用造成的问题。
5.2 Unified Send 与身份/能力矩阵
unified_send.go、identity_contract.go 和 im_contract.go 将发送动作从“按 API 名称选命令”提升为“按目标、身份与消息能力选择执行器”。
推荐的决策维度包括:
| 维度 | 示例 |
|---|---|
| 目标 | 单聊、群聊、机器人会话 |
| 身份 | 用户身份、机器人身份、应用身份 |
| 内容 | text、markdown、card、media |
| 能力 | 是否允许主动发送、是否支持回复、是否支持卡片更新 |
| 上下文 | profile、tenant、conversation |
这种能力矩阵比在每条命令内写条件分支更易审计。发生能力不匹配时,应在真正发起网络请求前失败,并返回建议使用的 route。
可复用原则
通讯录中的“读取、邀请、修改、删除”,文档中的“读取、创建、编辑、分享、删除”,都应建立身份与能力矩阵。调用者表达的是业务意图,Runtime 决定具体执行入口。
5.3 im.message-list.v1 消息投影
消息列表相关代码将上游异构响应投影成稳定的版本化结构。核心思想是:保留原始信息的同时,提供统一的机器字段。
典型规范字段包括:
messageIdconversationIdsenderId/senderNamemessageTypetext或规范化内容createdAtreplyToMessageIdraw(必要时用于诊断)hasMore/nextCursor
版本号的意义是允许未来增加或调整字段,而不破坏依赖 v1 的 Agent 与脚本。
可复用原则
- 通讯录:定义
directory.user-list.v1、directory.department-list.v1。 - 文档:定义
document.search-result.v1、document.block-list.v1。 - 云盘:定义
drive.file-list.v1、drive.transfer-result.v1。
不要让自动化直接依赖供应商原始响应;应通过投影层建立稳定域模型。
5.4 分页完整性与有界执行
PR 统一增强了消息、会话和成员列表的分页处理。一个健壮的列表命令至少需要:
- 明确单页与自动翻页模式;
- 返回
hasMore和nextCursor; - 支持
maxPages、maxItems等硬边界; - 检测游标不前进或循环;
- 去重并保持稳定顺序;
- 明确结果是完整集合还是截断集合;
- 在中途失败时返回已完成量和失败位置。
分页不是 UI 细节,而是数据完整性契约。尤其在“先查再写”的 Agent 流程中,静默截断会导致错误对象被操作。
当前需关注的问题
本次分析发现 +conversation-list 的单页模式存在一个边界风险:代码可能在解析下一页游标前提前退出,最终出现 hasMore=true 但 nextCursor=0。这不会否定整体设计,但应在合并前补回归测试并修复。
5.5 原子导出与资源下载
新增或强化的消息导出、资源下载路径采用“临时文件 -> 完整写入 -> 校验 -> 原子替换”的思路,避免失败时留下看似成功的残缺文件。
推荐流程:
解析目标
-> 校验输出路径与权限
-> 创建同目录临时文件
-> 有界分页拉取/流式下载
-> 校验数量、大小或摘要
-> fsync/close
-> 原子 rename 到最终路径
-> 返回 typed receipt
失败时删除临时文件,保留已有最终文件,并返回失败阶段、已处理数量及是否可重试。
可复用原则
该模式适用于:通讯录批量导出、文档离线备份、附件下载、云盘迁移、知识库归档以及审批记录导出。
5.6 +chat-create 与 +messages-reply
补齐这类语义型 shortcut 的意义在于构建完整 Golden Route:用户不需要先理解底层产品 API,再自己拼接参数。命令命名直接对应业务意图,Schema 则描述必要约束。
设计原则是:
- Shortcut 只暴露稳定、常用的业务参数;
- 复杂底层参数放入高级 Reference;
- 输出统一 envelope;
- 目标解析复用 Resolver;
- 写操作具备 preflight、明确身份和结构化回执。
5.7 event +listen-im
新增 IM 事件监听入口,将底层事件总线能力收敛为 Agent 易理解的生命周期命令。文档进一步拆出 keys、lifecycle、operations、output 四个主题,说明事件能力被视为长期运行流程,而不只是一次 API 调用。
事件监听需要明确:
- start、status、stop 的生命周期;
- profile 与租户隔离;
- endpoint/key 的稳定标识;
- 前台与后台模式;
- 超时、重连和退出语义;
- 事件 envelope 与消息投影;
- 重复事件、顺序和幂等边界。
可复用原则
通讯录变更事件、文档协作事件、云盘文件事件都可以复用同一监听骨架,只替换事件类型与投影器。
5.8 结构化错误与服务端失败分类
internal/errors 与 server_failure_classifier.go 将错误从一段不可解析文字升级为类型化结果。稳定错误至少应包含:
codemessagestageretryabledetailssuggestedAction- 必要的 request/trace 标识
关键分类包括:参数错误、目标未命中、目标歧义、身份不匹配、能力不支持、权限不足、限流、服务端失败、分页协议异常和文件提交失败。
错误分类的主要消费者不只是人,还包括 Agent 的下一步决策。因此 suggestedAction 应可执行,例如“提供 conversationId”“选择一个候选用户”“切换 bot identity”,而非笼统写“请重试”。
5.9 Profile 一致性
新增 profilectx 并调整 auth/profile 相关逻辑,目的是保证目标解析、API 调用和事件监听使用相同的身份上下文。跨 profile 漂移是多租户 CLI 中非常隐蔽的风险:解析可能在 A 租户命中对象,写操作却在 B 租户执行。
可复用规则:
- profile 在入口解析一次并向下传递;
- Resolver 结果记录 profile/tenant;
- 执行器不得静默回退到另一个默认 profile;
- 批处理账本记录每项使用的 profile;
- 事件监听 key 包含足够的上下文隔离信息。
5.10 隐藏兼容别名
PR 保留必要的参数或命令别名,但通过 metadata/schema 控制它们不再成为 Agent 的首选入口。这实现了“兼容旧调用,但不继续传播旧范式”。
正确的兼容策略应区分:
- Runtime compatibility:旧命令仍可运行;
- Discovery visibility:新用户和 Agent 默认看不到旧入口;
- Documentation priority:文档只推荐 Golden Route;
- Deprecation observability:能够统计旧入口使用情况;
- Removal criteria:达到明确阈值后再移除。
5.11 Shortcut 部分修改详解
当前 #860 共修改 44 个 internal/shortcut 文件,其中 26 个生产 Go 文件、18 个测试文件。它不是简单增加命令数量,而是把 Shortcut 从“调用 MCP 的便捷包装”升级为以下分层执行系统:
Shortcut 声明与 Cobra 编译
-> 本地参数/约束校验
-> 自然目标解析与全量预检
-> 身份/能力路由
-> MCP 读写隔离与 dry-run
-> 有界分页或批量执行
-> 统一领域投影
-> 完整性/失败 ledger
-> 原子导出或安全资源落盘
5.11.1 Shortcut 框架:声明能力,而不是在命令里重复装配 Cobra
internal/shortcut/types.go 和 internal/shortcut/runner.go 扩展了通用声明模型:
| 修改 | Runtime 行为 | 价值 |
|---|---|---|
Flag.Shorthand |
所有 flag 类型统一通过 Cobra 的 BoolP/IntP/StringP/StringSliceP 注册 |
--output 可安全提供 -o,不需要每个命令单独实现 |
Shortcut.Aliases |
将兼容命令映射到同一个执行实现 | 保留旧调用,但 canonical Schema 和文档仍只推荐主入口 |
SinglePositionalAliasFor |
单个位置参数在校验前归一化为指定 flag;与显式 flag 同时出现时拒绝 | 为搜索类命令提供兼容体验,同时避免形成第二套参数契约 |
Constraint |
at_least_one、exactly_one、mutually_exclusive 由 Runner 统一执行并投影到 Runtime Schema |
Help、Runtime 与 Agent Schema 共用参数关系 |
Changed、StrFirst、IntFirst |
能区分“用户显式输入”和“默认值”,并统一处理兼容别名 | 防止默认值错误覆盖旧参数或触发不适用校验 |
Runner 的执行顺序也被固定为:位置参数归一化 → required/enum 校验 → 跨参数约束 → 自定义校验 → 风险确认 → Execute。这样可以保证明显错误和未确认写操作不会到达 MCP。
读写调用进一步分离:CallMCPData 只允许符合只读命名契约的工具在 dry-run 中执行;CallMCPWriteData 在 dry-run 下直接 fail closed。多步写 Shortcut 必须自己输出 plan,不能借“为了拿返回值”之名在预览阶段执行写入。
5.11.2 Target Resolver:把名称解析变成共享基础设施
internal/shortcut/targetresolver/resolver.go 新增了独立解析层,核心类型包括:
Status:resolved、ambiguous、not_found、incomplete;IdentityRequirement:区分下游需要userId、openDingTalkId或任一稳定身份;UserResolution/ChatResolution:返回规范目标、匹配方式和 profile;Reader:只依赖只读CallMCPData,便于 Smart Shortcut、事件入口和测试共同复用。
群目标解析采用以下 fail-closed 算法:
cid...形式直接识别为稳定openConversationId,不做名称搜索;- 群名调用
im/search_groups,每页 10 条,最多 40 页; - 对候选按稳定 ID 去重;精确名称优先,但多个精确同名仍然算歧义;
hasMore=true时必须存在且推进nextCursor;- 满页但无分页元数据、游标停滞或达到页数上限时返回
resolution_incomplete; - 只有完整候选集中的唯一目标才允许继续执行。
批量解析 ResolveUsers/ResolveChats 会先解析全部目标并收集结构化失败;任一目标未命中或有歧义,就在写操作开始前整体停止。它解决了过去每个 +dm、+send-to-group、+group-members 自己搜索并默认取首项的问题。
需要注意:群名解析已经显式证明跨页候选完整;用户解析目前依赖 search_contact_by_key_word 单次响应提供完整候选,后续若通讯录接口引入分页,应把相同的完整性规则扩展到用户 Resolver。
5.11.3 身份与能力契约:先判断能不能做,再选择工具
internal/shortcut/chat/identity_contract.go 把 user、bot、webhook 三种身份的能力声明为矩阵,而不是散落在各分支的隐含知识:
| 身份 | 目标 | 内容 | 自然目标 | 幂等 | 批量 ledger |
|---|---|---|---|---|---|
| user | 群、单聊 user/openDingTalkId | text、markdown、image、file,audio/video 按 file 发送 | 群名、姓名 | 支持 | 否 |
| bot | 单群、多群、批量单聊 | text、markdown | 不支持 | 不支持 | 多群支持 |
| webhook | token 所属群 | text、markdown | 不支持 | 不支持 | 否 |
internal/shortcut/chat/im_contract.go 同时把“不支持什么”也变成可测试契约,例如 thread write、bot rich media、card action callback 和 Range 续传明确标记为不支持,并给出替代路径。这一点很重要:Agent 不应通过试错来发现能力边界。
5.11.4 +messages-send:统一发送入口内部做严格能力路由
internal/shortcut/chat/unified_send.go 将 user、bot、webhook 的发送入口合并为一个语义命令,但没有把底层差异抹平:
- user 目标必须在群、群名、userId、姓名、openDingTalkId 中恰好选择一个;
- bot 必须提供
robot-code,且群目标与批量单聊目标必须二选一; - webhook 的目标由 token 决定,拒绝额外群或用户目标;
@参数按身份和群聊/单聊分别校验;uuid/idempotency-key仅允许下层真实支持的 user 路径;- bot/webhook 在网络调用前拒绝 image/file/audio/video;
- 内容正文、
media-id和本地文件互斥,并自动推导msg-type。
user 的文件发送被拆成上传与消息发送两个动作,上传超时为 10 分钟;dry-run 只输出两步 plan。bot 多群发送最多 100 个目标,groups-file 必须是工作区内不超过 1 MiB 的普通文件,解析后去重,再通过 im.batch-write.v1 返回逐目标成功/失败账本。
batch_write.go 保持输入顺序,单项失败后继续其余项,但不自动重试写操作,因为远端报错时投递状态可能未知。代价是当前批量执行为顺序调用,优先可审计性和限流安全,而不是最大吞吐量。
5.11.5 Smart Shortcut 变薄:只组合公共能力
Smart 层的主要变化不是继续增加本地业务逻辑,而是把已有命令改造成公共组件的适配器:
| Shortcut/文件 | 修改后的职责 |
|---|---|
smart/dm.go |
解析自然用户目标后,委托统一 user markdown 发送器 |
smart/send_to_group.go |
解析群名或稳定 ID 后,委托同一发送器 |
smart/search_msg.go |
在搜索前完成群和发送者消歧,再使用公共消息投影 |
smart/at_me.go |
使用公共目标、分页和消息结果语义 |
smart/thread_replies.go |
复用 ProjectMessageV1,不再维护线程专属返回结构 |
smart/resolve.go |
旧局部解析辅助函数迁移到 targetresolver |
这使 Golden Route 保持语义清晰,同时底层身份、消息字段和失败行为只维护一份。
5.11.6 消息读取:从“返回数组”升级为 im.message-list.v1
internal/shortcut/chatmsg/chatmsg.go 建立所有列表、搜索、mget、@me 和线程读取共享的投影核心 ProjectMessageV1。消息行统一包含可获得的:
messageId / conversationId / threadId
sender / senderId / senderType
messageType / text / createTime / updateTime
reactions / quotedMessage / forwarded / resourceRefs
投影层做了几项关键防御:
- 同一语义字段兼容不同下层 key,但不会猜测缺失的 sender type;
- 富文本卡片只提取已识别的正文块,普通文本中的 JSON 片段保持原样;
- 无法解密的密文显示为明确标记,不把 base64 当正文;
- 引用消息做一层投影,避免递归链或循环;
- 合并转发递归使用同一投影;
- 资源从当前、引用和转发子消息中深度提取,并生成可执行下载参数;
- reaction 使用下层已内联的数据,不额外制造网络请求。
Envelope 默认保守地令 complete=false。只有拿到可靠分页事实时才允许证明完整;消息接口真正可继续执行的边界是末条消息的 createTime,因此 nextPage 发布 time + direction,而不是盲目把下层 cursor 暴露成 CLI 参数。
5.11.7 有界分页:完整、截断和失败必须可区分
smart/chat_messages.go 将消息读取拆为目标编译、单页收集、全量收集、投影、资源下载和导出六个阶段。全量模式具备:
page-limit默认 50、硬上限 500;max-results结果上限;- 稳定
messageId跨页去重; - 时间边界停滞检测;
hasMore=true但空页、缺边界或缺分页元数据时停止;stopReason区分source_complete、single_page、page_limit、result_limit、read_failure和pagination_error;- 中途失败保留已读结果,并用
partial/failures/failedCount显式标记。
chat_conversation.go 为会话列表加入同类的 page-all/page-limit、稳定 ID 去重和游标停滞检测,同时修正一个关键顺序问题:即使只读取一页,也必须在退出前解析 nextCursor,否则会出现 hasMore=true 却无法继续的结果。
smart/group_members.go 则建立 im.group-members.v1:用户和机器人分别进入 bucket;用户成员自动翻页并按 openDingtalkId 去重,机器人按下层全量结果投影。一个 bucket 失败时,另一个成功 bucket 仍可返回,但整体必须标记 partial 和 failures。
5.11.8 本地校验、导出和下载:错误尽量发生在网络调用前
新增的 smart/local_chat_validation.go 集中支持:
RFC3339、YYYY-MM-DD HH:mm:ss、YYYY-MM-DD三种时间格式;- 显式
limit/count/days必须为正数; - 分页默认值只在值为零时回退;
- 本地验证错误携带稳定 reason 和可执行 action。
消息 JSON 导出与资源下载共享文件安全边界:
- 只接受工作目录内相对路径;
- 同时识别 Unix 根路径、Windows 盘符、反斜杠和 portable
..逃逸; - 解析父目录 symlink,防止最终路径逃出工作区;
- 默认 no-clobber,覆盖必须显式声明;
- 先写同目录临时文件,完成写入、sync、close 后再原子发布;
- 失败时删除临时文件,不留下看似成功的半成品。
资源下载明确采用整文件重试而非 Range 续传。这个限制被写入能力契约,避免文档或 Agent 宣称不存在的断点续传能力。
5.11.9 新增和强化的 Golden Route
+chat-create:先解析所有自然成员和可选群主,整体预检成功后只创建一次;默认群主必须能从当前 profile 中取得并加入成员集合。+chat-update:群名或稳定 ID 统一解析,只承诺当前真实支持的改名能力。+messages-reply:可先读取原消息自动补齐引用发送者;dry-run 返回引用上下文和真实 transport plan;成功后补充消息、会话、线程、幂等和 delivery status。+chat-members-list:统一群目标,区分 users/bots,提供 bucket 完整性。+chat-messages:统一群聊/单聊自然目标、分页、消息投影、资源和导出。+messages-send:作为高级统一发送入口;+dm和+send-to-group继续承担更窄、更易选路的常用入口。
这体现了 Golden Route 的正确含义:不是强迫所有意图只剩一个巨型命令,而是为每类意图保留一个推荐入口,公共执行逻辑在下层复用。
5.11.10 测试重点与整体评价
18 个 Shortcut 测试文件主要固定以下不变量:
- 自然目标零命中、多命中、跨页同名和游标停滞时禁止写入;
- dry-run 中写调用为零,确认后写调用次数精确;
- canonical 参数与隐藏 alias 生成相同 MCP payload;
- 消息身份、正文、引用、转发、reaction、资源和分页投影一致;
- 页数/结果上限、中途失败和部分结果不会被标记为完整;
- Unix/Windows 路径、symlink、no-clobber 和原子发布边界;
- 所有公开 Shortcut 均进入 Schema 或有精确、受评审的 exclusion。
Shortcut 改造的核心价值可以概括为:语义入口仍然轻量,但目标解析、能力判断、完整性证明和安全落盘已经成为 Runtime 强约束。 当前仍需持续关注三点:unified_send.go 参数面较大、下层仍大量使用 map[string]any 做兼容投影、用户自然目标的候选完整性尚未像群目标一样显式分页证明。
6. 文档架构优化
本次文档改造的核心是“分层而非堆叠”:
SKILL.md
负责意图识别、入口选择和最短路径
|
+-- intent-guide.md
| 负责意图到命令的系统映射
|
+-- contracts.md / runtime-contract.md
| 负责稳定输入输出与错误约束
|
+-- product/reference docs
负责参数细节、边界与复杂示例
这类结构可以降低主 Skill 的上下文消耗,同时避免同一规则复制到多处后发生漂移。
7. 逐文档总结(30 份)
文档变更可以先按职责理解,再查看逐文件细节:
| 文档组 | 数量 | 主要职责 | 优化方向 |
|---|---|---|---|
| Mono | 4 | 全产品入口和产品索引 | 同步 Golden Route,避免复制领域细节 |
| Chat Skill 与总览 | 6 | IM 意图路由、总览和公共合同 | 收敛入口,建立独立 contracts |
| Chat 卡片 | 4 | 卡片模型与生命周期 | 按 create/update/callback/schema 拆分 |
| Chat 领域子文档 | 6 | bot、会话、群、消息及旧工作流 | 对齐新 Runtime,删除重复路由源 |
| Event | 6 | IM 事件监听 | 按 keys/lifecycle/operations/output 分层 |
| Shared | 4 | 跨产品运行约束 | 统一错误、profile 和 Runtime contract |
下面每份文档均按“改了什么—为什么—如何复用”三个问题进行总结。
7.1 Mono 文档
1. skills/mono/SKILL.md
- 调整 IM 意图的默认路由和入口说明。
- 将运行时已具备的统一消息、会话和事件能力呈现给单体 Skill。
- 强调优先使用稳定 shortcut,底层命令作为高级或兼容入口。
- 复用价值:任何全产品聚合 Skill 都应只维护意图索引,不复制领域手册。
2. skills/mono/references/best_practices/01-messaging.md
- 更新消息发送、回复、读取等最佳实践。
- 将自然目标解析、身份选择和分页边界纳入标准流程。
- 复用价值:最佳实践文档应描述决策原则,不只是展示命令样例。
3. skills/mono/references/products/chat.md
- 对齐新的 chat shortcut、统一输出和能力边界。
- 收敛旧脚本路径,避免文档继续引导 Agent 选择已被 Runtime 吸收的脚本。
- 复用价值:产品 Reference 必须与 Schema 的可发现能力同步更新。
4. skills/mono/references/products/event.md
- 引入
event +listen-im及其生命周期说明。 - 明确事件监听与普通一次性命令的差异。
- 复用价值:所有长生命周期能力都应提供 start/status/stop 和恢复语义。
7.2 Chat Skill 与总览文档
5. skills/multi/dingtalk-chat/SKILL.md
- 重构 chat 的核心意图路由,突出 Golden Route。
- 增加统一发送、会话创建、消息回复、列表、导出等入口。
- 将详细合同和高级示例下沉到 Reference,降低主入口复杂度。
- 当前版本为 9,928 bytes,已进入 10,000 bytes 上下文预算,但只剩 72 bytes 余量,应继续把细节下沉到 Reference。
- 复用价值:领域 Skill 应是“路由器”,不是完整 API 百科。
6. skills/multi/dingtalk-chat/references/01-messaging.md
- 更新端到端消息操作最佳实践。
- 强调先解析目标、再做能力判断、最后执行写操作。
- 补充分页、回复、文件处理等边界。
- 复用价值:将“解析—计划—执行—回执”固化为跨产品写操作模板。
7. skills/multi/dingtalk-chat/references/chat.md
- 大幅重构 chat 总参考,覆盖新的 shortcut 和 Runtime 契约。
- 统一参数命名、输出结构、错误处理和高级入口定位。
- 减少与子文档的重复,将细节按主题拆分。
- 复用价值:领域总览应负责导航和共享概念,具体操作落到子 Reference。
8. skills/multi/dingtalk-chat/references/intent-guide.md
- 建立用户意图到 Golden Route 的明确映射。
- 说明目标是人、群、会话或消息时分别如何选择命令。
- 降低“多个命令看起来都能完成任务”造成的路由不确定性。
- 复用价值:通讯录和文档也应维护机器可校验的 intent-route 表。
9. skills/multi/dingtalk-chat/references/contracts.md
- 新增集中式契约文档。
- 固定消息列表、写操作回执、批处理账本和错误 envelope 等公共结构。
- 将契约与教程分离,便于版本化和自动检查。
- 复用价值:每个领域都应有唯一的 contract source of truth。
10. skills/multi/dingtalk-chat/references/chat-emoji-list.md
- 对齐 emoji 相关命令、目标和消息标识参数。
- 使轻量功能也遵循统一会话/消息身份语义。
- 复用价值:边缘功能不能绕过统一 Resolver 和契约。
7.3 Chat 卡片文档
11. skills/multi/dingtalk-chat/references/card/create.md
- 新增卡片创建流程说明。
- 区分卡片定义、实例创建和消息投递,避免一步调用承载过多隐式行为。
- 复用价值:复杂对象创建应拆成资源定义、实例化和发布阶段。
12. skills/multi/dingtalk-chat/references/card/update.md
- 新增卡片更新操作说明。
- 强调实例标识、可更新字段和生命周期边界。
- 复用价值:文档更新、表格更新等都应区分 create contract 与 update contract。
13. skills/multi/dingtalk-chat/references/card/callback.md
- 新增卡片回调与交互事件说明。
- 将回调输入视为结构化事件,而不是普通消息文本。
- 复用价值:交互式文档组件、审批回调也可复用事件 envelope。
14. skills/multi/dingtalk-chat/references/card/schema.md
- 新增卡片 Schema 说明。
- 集中描述字段结构和约束,减少 create/update 文档重复。
- 复用价值:把数据模型与操作教程分开,Schema 可单独校验和演进。
7.4 Chat 领域子文档
15. skills/multi/dingtalk-chat/references/chat/chat-bot.md
- 更新机器人发送、广播及身份能力说明。
- 旧脚本能力被收敛进 Runtime,文档不再要求 Agent 拼装脚本流程。
- 注意:文档部分位置使用
results,而 Runtime 实际批处理字段为succeeded,需统一。 - 复用价值:文档字段名必须由合同或测试生成,避免手工漂移。
16. skills/multi/dingtalk-chat/references/chat/chat-conversation.md
- 更新会话创建、列表和目标标识说明。
- 补充游标、分页和会话类型边界。
- 复用价值:任何容器类资源都应区分 canonical ID、display name 与 page cursor。
17. skills/multi/dingtalk-chat/references/chat/chat-group.md
- 更新群成员、群信息与群目标解析流程。
- 统一群名与群 ID 的解析/歧义处理。
- 复用价值:部门名、空间名、目录名同样需要唯一解析和候选返回。
18. skills/multi/dingtalk-chat/references/chat/chat-message.md
- 更新消息读取、回复、导出和资源下载说明。
- 对齐
im.message-list.v1投影及分页元数据。 - 复用价值:把列表 contract 与后续动作需要的 canonical ID 同时输出。
19. skills/multi/dingtalk-chat/references/chat/chat-workflows.md(删除)
- 删除与 SKILL、intent guide 和领域子文档大量重叠的工作流集合。
- 旧文档容易形成第二套意图路由源。
- 复用价值:当工作流可由 Golden Route 与合同组合推导时,不应继续维护重复手册。
20. skills/multi/dingtalk-chat/references/lite-recipes.md(删除)
- 删除过短且容易过时的 recipe 集合。
- 将典型路径并入主 Skill 或更权威的 Reference。
- 复用价值:减少“看似方便但缺少边界”的示例,避免模型只复制 happy path。
7.5 Event 文档
21. skills/multi/dingtalk-event/SKILL.md
- 增加 IM 监听的意图入口与生命周期路由。
- 将普通事件命令和长期监听操作区分开。
- 复用价值:事件领域 Skill 应首先判断用户要“查询配置”还是“启动持续进程”。
22. skills/multi/dingtalk-event/references/event-im.md
- 大幅更新 IM 事件总参考。
- 串联配置、启动、运行、输出、停止和排错。
- 将细节拆到四个新子文档,自己承担导航职责。
- 复用价值:长流程总文档应提供生命周期地图而非重复所有参数。
23. skills/multi/dingtalk-event/references/event-im-keys.md
- 新增 endpoint、listener、profile 等关键标识说明。
- 明确 key 的生成、引用和隔离边界。
- 复用价值:后台任务、同步任务、订阅任务都需要稳定 task key。
24. skills/multi/dingtalk-event/references/event-im-lifecycle.md
- 新增启动、运行、状态、停止等生命周期说明。
- 描述前后台模式及退出后的状态语义。
- 复用价值:将长任务统一建模为显式状态机。
25. skills/multi/dingtalk-event/references/event-im-operations.md
- 新增常见操作和运维流程说明。
- 将查看状态、诊断、停止等操作从概念说明中拆出。
- 复用价值:后台服务文档应提供可操作 runbook。
26. skills/multi/dingtalk-event/references/event-im-output.md
- 新增监听输出格式及字段解释。
- 明确事件 envelope 与 IM 消息投影之间的关系。
- 复用价值:通讯录、文档事件应共享 envelope,仅替换 payload contract。
7.6 Shared 文档
27. skills/multi/dws-shared/SKILL.md
- 更新多产品共享约束和 Reference 导航。
- 将 Runtime contract 与错误码作为跨领域公共基础设施。
- 复用价值:共享 Skill 只承载真正跨域的稳定规则,领域语义仍留在各自 Skill。
28. skills/multi/dws-shared/references/error-codes.md
- 扩展结构化错误类别、可重试性和建议动作。
- 支撑 Target Resolver、服务端失败分类和文件流程。
- 复用价值:错误码应跨产品统一命名,领域细节放入
details。
29. skills/multi/dws-shared/references/global-reference.md
- 更新全局参数、profile、输出和运行约束。
- 明确公共规则的权威来源,减少 chat/event 文档重复。
- 复用价值:全局 Reference 应稳定且少变,产品差异通过链接下沉。
30. skills/multi/dws-shared/references/runtime-contract.md
- 新增 Runtime 公共契约说明。
- 固定 envelope、错误、批处理、分页和 profile 传播等跨产品行为。
- 复用价值:通讯录、文档、云盘接入时应直接复用,而非重新设计返回结构。
8. 被删除脚本的意义
PR 删除 mono 与 multi chat 下的以下脚本:
bot_broadcast.pychat_export_messages.pychat_history_with_user.py
删除并不意味着能力减少,而是能力已进入可测试、可发现、可治理的 Runtime。脚本适合验证原型,但长期作为 Agent 主路径会带来参数契约不可发现、错误格式不一致、身份上下文丢失和重复分页逻辑等问题。
迁移准则:当一个脚本成为稳定业务能力后,应将核心逻辑提升到 Runtime,生成 Schema,补充契约测试,然后从主 Skill 中撤下脚本入口。
9. Policy 与测试体系
9.1 Multi IM Skill Chain Policy
新增 scripts/policy/multi-im-skill-chain,通过意图测试数据检查关键路径是否在 Skill、Reference、Schema 与 Runtime 之间闭环。其价值是防止以下回归:
- 文档推荐了不存在的命令;
- Runtime 已新增命令但 Schema 未暴露;
- 兼容别名重新成为首选;
- 同一意图再次出现多个 Golden Route;
- 关键参数或输出字段只在某一层存在。
当前 intent manifest 包含 9 个关键意图路由;PR 描述记录 make policy 通过。本文对代码和配置进行了静态核对,没有把该记录扩展表述为 GitHub CI 全绿。
9.2 Context Budget Policy
Skill 上下文预算检查用于控制入口文档大小。渐进披露只有在主 Skill 足够短时才有效。当前 chat Skill 为 9,928 bytes,刚好回到 10,000 bytes 预算内;架构方向正确,但余量很小,内容仍需继续去重或下沉。
9.3 测试分层
本次变更配套测试覆盖:
- Resolver 的唯一命中、多命中、未命中与输入类型;
- unified send 的目标和身份选择;
- 消息投影字段;
- 分页边界与兼容行为;
- 结构化错误和服务端失败分类;
- event 命令注册与生命周期;
- Schema/shortcut contract;
- mock MCP 端到端冒烟路径。
PR 描述记录 internal/app、internal/shortcut/chat 和 internal/shortcut/smart 等重点测试通过。本文分析的是远端 head 的 Git 对象,没有在当前 main 工作区切换分支重新运行完整测试;当前 GitHub CI 结论仍应以第 21 章列出的 workflow 状态为准。
10. 面向通讯录场景的复用蓝图
通讯录复用的重点不是照搬 IM 命令,而是把“找群/找人后执行动作”的模式转换为“找用户/找部门后执行动作”。核心差异在于通讯录写操作通常权限更高、影响范围更大,因此 Resolver 的唯一性和执行前计划需要更严格。
10.1 建议 Golden Routes
contact +resolve
contact +user-get
contact +user-list
contact +department-list
contact +member-list
contact +invite
contact +update
contact +export
event +listen-contact
10.2 Directory Resolver
集中接受姓名、手机号、邮箱、userId、unionId、部门名称和 deptId。输出唯一 canonical target 或候选列表,不允许高风险写操作在歧义状态下继续。
10.3 类型化契约
建议定义:
directory.user.v1directory.user-list.v1directory.department.v1directory.member-list.v1directory.batch-write-result.v1directory.change-event.v1
10.4 风险分级
- 只读查询:可在唯一命中后自动执行。
- 邀请/修改:必须显示 preflight plan。
- 删除/批量调岗:要求显式确认、严格唯一目标和可审计账本。
10.5 批处理账本
每条记录包含 input、resolved target、action、status、error、retryable 和 profile。这样部分失败可安全重试,不需要重跑已成功项目。
11. 面向文档、云盘和知识库的复用蓝图
文档类场景与 IM 的共同点是目标输入多样、读取结果需要稳定投影、长流程需要完整性保证;不同点是文档还涉及版本冲突、层级容器、权限继承和内容覆盖。因此在复用 Resolver 与 Runtime contract 的同时,应额外引入 revision/etag 和并发控制。
11.1 建议 Golden Routes
doc +resolve
doc +create
doc +read
doc +update
doc +export
doc +share
drive +download
drive +upload
wiki +resolve-node
event +listen-document
11.2 Document Target Resolver
统一解析 URL、docId、fileId、spaceId、workspaceId、知识库节点 ID、标题和路径。解析输出必须包含 product/resource type,避免将同形 ID 传给错误产品接口。
11.3 Plan/Execute 分离
写文档、覆盖文件、调整权限、移动知识库节点前先生成计划:
{
"target": {"type": "document", "id": "..."},
"action": "replace-content",
"identity": "user",
"expectedRevision": "...",
"sideEffects": ["overwrite content"],
"recoverability": "revision-history"
}
计划可以独立验证权限、版本冲突和副作用;确认后才执行。
11.4 列表与搜索契约
搜索结果必须区分 exact、fuzzy 和 candidate,返回 canonical URL/ID、容器、资源类型、权限摘要以及分页状态。不要只返回标题字符串。
11.5 原子输出与并发控制
- 导出使用临时文件和原子替换。
- 更新使用 revision/etag 防止覆盖他人修改。
- 上传返回摘要、大小和最终资源 ID。
- 长迁移返回 checkpoint 与逐项账本。
12. 可复用的落地模板
12.1 新领域接入步骤
- 列出用户真实意图,而非先列 API。
- 为每个意图指定唯一 Golden Route。
- 设计统一 Target Resolver 和 canonical target。
- 建立身份/能力矩阵。
- 定义版本化输入、列表、写回执和错误契约。
- 为长流程增加 maxItems、maxPages、timeout、checkpoint。
- 将写操作拆为 plan 和 execute。
- 生成或同步 Schema metadata/hints/registry。
- 编写短 Skill、意图指南、合同和分主题 Reference。
- 增加意图链路、上下文预算、Schema 和契约测试。
12.2 推荐目录结构
skills/multi/dingtalk-<domain>/
SKILL.md
references/
intent-guide.md
contracts.md
<domain>.md
<topic-a>.md
<topic-b>.md
internal/shortcut/
<domain>/
<domain>resolver/
scripts/policy/
<domain>-skill-chain/
12.3 Golden Route 评审问题
- 一个自然语言意图是否只有一个默认入口?
- shortcut 是否隐藏了供应商 API 的非必要复杂度?
- 兼容入口是否仍可运行但不会被 Agent 优先发现?
- Resolver 是否统一处理 ID、名称、URL 和多候选?
- 写操作是否在执行前完成身份和能力校验?
- 输出是否有稳定版本?
- 列表是否明确完整、截断与下一页状态?
- 错误是否能指导 Agent 下一步动作?
- Skill、Reference、Schema 与 Runtime 是否有自动一致性检查?
13. PR #860 当前风险收口状态
| 评审问题 | 当前整体实现 | 判断 |
|---|---|---|
+conversation-list 单页模式丢失 nextCursor |
将 cursor 解析移动到单页退出判断之前,并补充失败边界测试 | 已修复 |
hasMore=true 但 cursor 缺失、无效或不前进 |
增加 missing/invalid/stalled cursor 测试 | 已强化 |
| Chat Shortcut 未全部进入 Schema | 从 50/97 提升到 97/97,删除 47 项临时 exclusion | 已解决 |
高风险示例直接展示 --yes |
文档和命令示例改为先运行或 --dry-run,由 Runtime 要求确认后再追加 --yes |
已改善 |
| 跨平台输出路径判断和覆盖替换不完整 | 统一处理 Unix/Windows 路径语义,并以 build tags 分离 os.Rename 与 windows.Rename |
已加固 |
chat bot 文档 results 与 Runtime succeeded 可能不一致 |
当前 diff 中未见由单一 typed source 自动生成这两个名称 | 仍需确认 |
| Chat Skill 上下文预算偏紧 | 已通过拆分 Reference 和删除重复文档缩短主 Skill,仍应持续由 budget policy 约束 | 持续治理 |
| 兼容别名缺少退出观测 | 已增强 alias/canonical payload 等价测试,但未建立使用量观测或移除阈值 | 长期项 |
| 真实线上语义 | 单元测试和 mock MCP 能证明本地契约,不能证明真实权限、MCP 响应和服务端可用性 | 需要受控 E2E |
14. PR #860 整体架构结论
PR #860 的核心贡献,是把 IM 能力从“散落的命令和教程”升级为“可解析、可计划、可执行、可验证的意图系统”。其最重要的架构资产包括:
- Resolver:统一对象身份;
- Golden Route:统一意图入口;
- Capability Matrix:统一身份与能力判断;
- Versioned Contract:统一机器输出;
- Bounded Execution:统一分页和长流程边界;
- Typed Error Ledger:统一失败处理与恢复;
- Progressive Documentation:统一知识组织;
- Policy Gates:统一防漂移机制。
这些模式与 IM 本身无强绑定。通讯录的“找人/找部门”、文档的“找资源/改内容”、云盘的“找文件/迁移”、知识库的“找节点/调整结构”都面临同一类问题。复用时应迁移完整链路,而不是只复制某个 shortcut:
意图设计
-> Resolver
-> Golden Route
-> Plan/Capability Check
-> Bounded Runtime
-> Versioned Result/Error
-> Documentation + Schema + Policy
只有整条链路同时落地,才能真正降低 Agent 的选择成本、减少误操作,并让新领域能力持续演进而不重新陷入命令、文档和实现相互漂移的问题。
15. 产品化交付闭环
15.1 为什么 Runtime 完成不等于 PR 完成
PR #860 同时处理两类问题:一类是命令行为本身,另一类是 Agent 能否发现、正确选择并安全执行这些行为。只有 Runtime、Registry、Schema、selection hints、风险 metadata、Skill、Policy 和测试同时闭环,才能把“隐藏在代码里的能力”升级为“可交付产品能力”。
大行数主要来自重新生成并提交的 Schema catalog 和 Agent metadata,不能等同于 6 万余行手写业务逻辑。评审时应将 authored source、Runtime、generated artifacts、文档和测试分开看。
15.2 五个交付收口方向
- 能力发布完整化:剩余 47 个公开 Chat Shortcut 从临时 exclusion 转为正式 Registry 和 Schema 能力,使 Chat 达到 97/97。
- 安全元数据类型化:为 47 个命令逐一声明 effect、risk、confirmation、idempotency、interface mode 和 runtime gate。
- 参数前置校验:时间、页大小、回溯窗口等明显错误在本地拒绝,不再发起无效远端调用。
- 运行时边界收口:修复单页 cursor、补
-o、增强跨平台输出路径并扩大目标消歧测试。 - 交付证据闭环:重新生成 Schema/Agent metadata,强化生成漂移、契约完整性和 changed-code coverage 门禁。
16. Schema 发布与能力治理
16.1 从 50/97 到 97/97
PR #860 在 internal/cli/schema_command_registry/products/chat.json 中补齐 47 个 canonical shortcut,并从 schema_command_exclusions.json 删除整个 chat-shortcuts-pending-schema-curation 临时排除组。
这一步的意义不是单纯“数字补齐”,而是完成以下状态转换:
公开可执行、但 Schema 暂未评审
-> authored Registry 有正式记录
-> selection hints 能指导 Agent 何时用/何时不用
-> metadata 声明风险和确认方式
-> generated catalog/Agent metadata 可发现
-> completeness test 保证不再退回临时排除
关键指标变化:
| 指标 | 改造前 | PR #860 当前 head |
|---|---|---|
| Chat Schema Shortcut | 50 | 97 |
| 全部公开 Shortcut Schema 覆盖 | 218 / 265 | 265 / 265 |
| Schema catalog 工具数 | 850 | 898 |
| Agent metadata 覆盖工具数 | 850 | 898 |
| hint tools | 1,852 | 1,948 |
| reviewed Agent examples | — | 1,108(1,084 contract + 24 dry-run) |
16.2 新发布的 47 个 Shortcut
为便于理解,可按业务域归为五组:
会话分类(3)
+category-add-conversation+category-list-conversations+category-remove-conversation
群管理(13)
+chat-add-bot+chat-audit-join+chat-get-by-id+chat-members-get+chat-mute-member+chat-quit+chat-remove-bot+chat-role-remove+chat-role-remove-user+chat-transfer-owner+chat-update+chat-update-icon+chat-update-settings
会话状态(7)
+conversation-clear-messages+conversation-clear-red-point+conversation-hide+conversation-mark-read+conversation-mark-unread+conversation-mute+conversation-set-top
Feed 与收藏(4)
+feed-group-query-item+flag-cancel+flag-create+flag-list
消息与资源(20)
+messages-add-emoji+messages-add-text-emotion+messages-batch-recall-by-bot+messages-batch-send-by-bot+messages-combine-forward+messages-create-text-emotion+messages-forward+messages-forward-topic+messages-list+messages-recall+messages-recall-by-bot+messages-remove-emoji+messages-remove-text-emotion+messages-resource-download+messages-resource-url+messages-send-by-bot+messages-set-pin+messages-set-top+messages-unset-pin+messages-unset-top
16.3 风险与确认元数据
47 个新增 metadata 的分布非常清晰:
| 类型 | 数量 | confirmation | runtime gate |
|---|---|---|---|
| 只读 / low | 8 | not_required |
none |
| 写操作 / medium | 36 | user_required |
typed_yes |
| 破坏性 / high | 3 | user_required |
typed_yes |
三个 high-risk 命令是:
chat.shortcut_chat_remove_botchat.shortcut_chat_role_removechat.shortcut_conversation_clear_messages
八个只读命令包括分类列表、按 ID 查群、成员获取、Feed 查询、收藏列表、消息列表、资源 URL 和资源下载。其余 39 个命令全部要求用户确认并由 Runtime 的 typed_yes 门禁执行。
这种分类实现了三个层面的一致性:
- Agent 在选择工具时能看到风险;
- 示例不会把确认当成默认参数;
- Runtime 即使被直接调用,也会阻止未经确认的写操作。
16.4 Authored Source 与生成物分离
PR #860 的权威编辑源主要是:
schema_command_registry/products/chat.json:命令身份和 canonical path;schema_hints/selection/chat.json:use_when、avoid_when和 source refs;schema_hints/metadata/chat.json:effect、risk、confirmation 等运行语义。
随后由生成流程更新:
schema_catalog/catalog.jsonschema_catalog/tools/chat.jsonschema_agent_metadata/chat.jsonschema_agent_metadata/index.jsonschema_agent_metadata_audit.jsonruntime-surface-completeness.json
复用到其他产品时,应优先评审 authored source 的准确性,再验证生成物无漂移。直接手改大型 catalog 会削弱可追溯性。
16.5 Selection Hints 的价值
每个新 Shortcut 都有独立的 use_when、avoid_when 和 source_refs。三者分别解决:
- 什么时候用:把用户意图映射到该工具;
- 什么时候不用:避免和相近工具误路由;
- 依据是什么:从生成结果追溯到 Registry 和文档锚点。
这比只提供命令描述更适合 Agent,因为工具选择的难点通常不是“工具做什么”,而是“在几个相似工具中为什么选这个”。
17. Runtime 安全与正确性加固
17.1 本地参数校验
新增 internal/shortcut/smart/local_chat_validation.go,集中实现:
- 默认分页上限归一化;
- RFC3339、
YYYY-MM-DD HH:mm:ss、YYYY-MM-DD三类时间格式检查; - 带稳定 reason 和 suggested action 的本地 validation error。
落地命令及边界:
| 命令 | 新增校验 |
|---|---|
+chat-messages |
--time 格式;--limit/--size/--page-size > 0 |
+thread-replies |
时间格式;显式 --limit > 0 |
+at-me |
--days 为 1~3650;--limit > 0 |
+unread-chats |
显式 --count > 0 |
核心原则是“能够在本地确定错误,就不要把它推给远端”。这样能减少无效请求,并让 Schema 约束、CLI 错误和测试保持一致。
17.2 破坏性确认门禁
internal/helpers/chat.go 为以下底层命令补上真实 Runtime 检查:
chat category deletechat clear-messages
缺少 --yes 时,命令返回 confirmation_required,列出确认目标和再次执行方式,并保证没有任何下游工具调用。补充测试同时验证:确认前零写入、确认后仅发生一次预期调用。
此外,群解散和升级外部群等示例不再直接展示 --yes;升级示例改用 --dry-run。这是一个重要的提示工程原则:
文档示例应该展示安全的第一步,而不是展示绕过交互确认的最终一步。
17.3 单页会话 cursor 修复
+conversation-list 的旧实现曾在非 --page-all 模式下先退出循环,再解析 nextCursor,可能返回 hasMore=true 但游标为零。PR #860 将 cursor 解析提前到退出判断之前。
修复后的行为:
- 单页结果保留可执行的下一页游标;
hasMore=true但游标缺失、无效或停滞时记录 pagination failure;--page-all才继续拉下一页;--page-limit保持有界。
这说明分页契约的完整性不仅适用于“拉完全部”,单页模式同样必须提供可靠 continuation。
17.4 通用 shorthand 支持
shortcut.Flag 新增 Shorthand 字段,统一注册逻辑从 Cobra 的 Bool/Int/StringSlice/String 切换到对应的 *P 版本。+chat-messages --output 因而获得 -o。
该改动是框架级能力,不只服务于当前命令。后续复用时需增加同一命令内 shorthand 唯一性检查,避免不同 flag 争用同一个短参数。
17.5 跨平台资源路径加固
原实现主要依赖当前操作系统的 filepath.IsAbs/Clean。在 Unix 上,Windows 盘符路径或反斜杠逃逸未必会按预期识别。PR #860 增加 portable 归一化:
- 将反斜杠转换为
/后再检查; - 识别 Unix 绝对路径;
- 识别 Windows
C:等盘符; - 统一拒绝
..和../逃逸; - 在父目录、相对路径和最终解析阶段复用同一判断。
- 用
file_replace.go与file_replace_windows.go的 build tags 分离平台实现:非 Windows 使用os.Rename,Windows 使用windows.Rename,保证覆盖写仍是原子替换。
该模式可直接用于文档导出、云盘下载、通讯录 CSV 导出和任何工作区内文件写入能力。
17.6 目标消歧与 fail-closed 测试
Resolver 实现与测试共同固定以下关键语义:
- 稳定 ID 永远不按名称搜索;
- 自然目标走 Resolver;
- 同名精确匹配仍保持歧义,不能偷偷选一个;
- 必须翻完候选页后才判断是否唯一;
- cursor 无法推进时 fail closed;
- 结构化错误保留候选对象;
- 外部联系人只要有可用 openDingTalkId 也可参与解析。
最重要的改进是“跨页后再唯一判定”。如果只看第一页就认为唯一,在第二页存在同名对象时会产生高风险误操作。
17.7 删除过时 hint 子命令
删除 dws chat send 和 dws chat history 两个仅用于提示的伪子命令。Golden Route 已通过 Shortcut 和 Schema 正式发布后,继续保留 hint 命令会污染命令树并形成第二套发现路径。
兼容不等于永远保留所有提示层。若入口已经由结构化 discovery 接管,应删除无法执行真实业务、只输出迁移提示的旧节点。
18. PR #860 文件分类总结
18.1 129 个文件按职责归类
| 文件组 | 数量 | 主要内容 |
|---|---|---|
| 生产 Go | 38 | App、错误、Resolver、Chat/Smart Runtime、契约、Policy 与生成别名 |
| Go 测试 | 30 | Resolver、分页、确认、文件安全、事件、契约及 coverage |
| Skill Markdown | 30 | Mono、Chat、Event、Shared 四层知识链路 |
| Schema / metadata / JSON | 17 | Registry、selection、risk metadata、catalog、Agent metadata 与 intent manifest |
| Skill 脚本 | 6 | 删除已被 Runtime 替代的重复 Python 路径 |
| 生成/审计脚本 | 6 | Skill 生成、Policy 检查、live audit 及其测试 |
| CI / Makefile | 2 | 接入 Policy、兼容性、覆盖率及平台 race 验证 |
18.2 Schema 文件逐项总结
| 文件 | 总结 |
|---|---|
schema_command_registry/products/chat.json |
补齐 canonical Shortcut,成为 Chat 发布权威源 |
schema_command_exclusions.json |
删除 47 项“待 Schema 评审”临时豁免,反向完整性转为硬约束 |
schema_hints/selection/chat.json |
为 Chat 工具补齐 use/avoid/source refs,强化 Agent 路由 |
schema_hints/metadata/chat.json |
为 Chat 工具声明 effect、risk、confirmation、idempotency 和 runtime gate |
schema_hints/runtime-surface-completeness.json |
更新 Runtime surface 覆盖指纹与统计 |
schema_catalog/catalog.json |
重新生成全局 catalog 索引 |
schema_catalog/tools/chat.json |
重新生成 Chat 的完整工具契约和示例 |
schema_agent_metadata/chat.json |
生成 Chat Agent 决策元数据 |
schema_agent_metadata/index.json |
更新全产品 metadata 索引和 898 工具统计 |
schema_agent_metadata_audit.json |
更新 coverage、source/surface hash 和审计结果 |
18.3 Runtime 文件逐项总结
| 文件 | 总结 |
|---|---|
internal/helpers/chat.go |
为删除分类、清空消息补确认门禁;安全化危险示例;删除旧 hint 子命令 |
shortcut/chat/chat_conversation.go |
修复单页模式 nextCursor 丢失 |
shortcut/chat/resource_download.go |
统一 Unix/Windows 绝对路径和 .. 逃逸判断 |
shortcut/chat/file_replace.go |
非 Windows 构建使用 os.Rename 作为原子替换边界 |
shortcut/chat/file_replace_windows.go |
Windows 构建使用 windows.Rename 支持覆盖已有目标 |
shortcut/runner.go |
所有 flag 类型支持 shorthand 注册 |
shortcut/types.go |
Flag 契约增加 Shorthand |
smart/local_chat_validation.go |
新增共享时间、页大小和结构化本地错误辅助函数 |
smart/chat_messages.go |
新增时间/页大小校验及 -o,复用默认 page limit |
smart/at_me.go |
限定 days 和 limit,组合资源下载校验 |
smart/thread_replies.go |
限定时间格式和 limit |
smart/unread_chats.go |
限定 count 为正数 |
smart/group_members.go |
复用统一默认 page limit 逻辑 |
18.4 Policy 文件总结
scripts/policy/multi-im-skill-chain/main.go 将工作目录、进程退出、文件打开和 Registry build/bind 抽成可注入函数。行为本身没有改变,但各种 setup failure、I/O failure 和 binding failure 现在可在单元测试中稳定覆盖。
这是一种值得复用的“测试接缝”设计:对进程边界做最小注入,不为测试重写业务逻辑。
18.5 安全示例收口示例
1. skills/mono/references/best_practices/01-messaging.md
- 将发送、机器人批量发送和消息转发示例中的默认
--yes去掉。 - 明确 Runtime 会先返回确认要求;用户确认后才以相同参数追加
--yes。 - 保留唯一目标解析、同 profile 稳定 ID 和未知投递状态停止重发等规则。
- 复用价值:所有写操作最佳实践都应展示“安全第一步 + 确认后续步骤”,不能把确认令牌写进首个示例。
2. skills/mono/references/products/chat.md
- 将“普通群升级为外部群”的正式执行示例改为
--dry-run。 - 删除直接带
--yes的示例,保留 extension JSON 的预演方式。 - 复用价值:不可逆转换、权限变更和内容覆盖应优先展示 dry-run/preflight。
18.6 测试体系总结
PR #860 的 30 个 Go 测试文件主要覆盖:
- 265/265 public Shortcut Schema 覆盖和 Chat 97/97;
- metadata 风险与 Runtime confirmation truth;
- 时间、页大小、回溯窗口等本地无网络校验;
- natural target、稳定 ID、同名候选和跨页消歧;
- 单页/全量分页、cursor 停滞、边界失败和部分结果保留;
- 资源下载的绝对路径、反斜杠、symlink、原子 no-clobber;
- 确认前零写调用、确认后精确一次调用;
- alias 到 canonical payload 的等价性;
- Multi IM Policy 的配置、I/O 和失败矩阵;
- 跨平台 changed-code coverage。
测试名大量增加 CrossPlatformCoverage 前缀,是为了让平台覆盖门禁识别相关测试。其积极意义是证据可追踪;长期应避免让命名约定取代真正的覆盖映射机制。
19. Go 文件优化专项总结
19.1 总体规模与演进主线
PR #860 的 Go 变更应按“生产实现”和“验证实现”分开理解:
| 类型 | 文件数 | 新增 / 删除 | 主要任务 |
|---|---|---|---|
| 生产 Go | 38 | +4,028 / -737 | 建立 Resolver、IM Runtime 契约、事件监听、错误/Profile、平台文件替换和 Policy 基座 |
| Go 测试 | 30 | +4,343 / -88 | 固定正常路径、失败边界、安全不变量、Schema/Runtime 一致性与跨平台覆盖 |
整体演进不是把更多逻辑堆进单个命令,而是逐步形成以下 Go 代码分层:
Cobra / App 层
负责命令注册、参数装配、profile 与进程生命周期
|
v
Shortcut / Smart 层
负责 Golden Route、业务校验、计划和结果组织
|
v
Target Resolver / Contract 层
负责规范目标、身份能力、版本化结果和错误语义
|
v
Helper / Transport 调用层
负责下游工具调用,不重复业务决策
|
v
Policy + Tests
验证 Runtime、Schema、文档和安全元数据保持一致
19.2 App、错误与上下文文件
| Go 文件 | 主要优化 | 设计价值 |
|---|---|---|
internal/app/event_command.go |
注册新的 event +listen-im 入口 |
将 IM 事件监听纳入正式内建命令树 |
internal/app/event_listen_im.go |
新增监听计划编译、自然目标解析、事件类型映射及 consume 生命周期委托 | 把长期事件订阅从参数拼装提升为可验证的计划执行 |
internal/app/runner.go |
增强多 profile 执行和错误结果组织 | 批量或多身份运行时保留逐 profile 的失败语义 |
internal/app/server_failure_classifier.go |
新增服务端业务失败分类器 | 将后端文本/元数据转换为稳定 reason、retryable 和行动建议 |
internal/auth/profiles.go |
收敛 profile 选择和传播方式 | 减少解析与执行使用不同租户身份的风险 |
internal/profilectx/profile.go |
新增轻量 profile context | 让 Resolver、Shortcut 和调用层共享明确身份上下文 |
internal/errors/errors.go |
扩展 typed error、server diagnostics 和结构化输出字段 | 使错误可被 Agent 解析并驱动后续动作 |
internal/cli/param_aliases_generated.go |
发布新增 IM 参数别名 | 兼容旧参数拼写,同时维持 canonical payload |
internal/helpers/aisearch.go |
补齐搜索目标兼容与参数映射 | 为自然人名解析提供更稳定的下层搜索入口 |
internal/helpers/chat.go |
对齐 Chat 底层命令边界、参数与确认相关行为 | 使 shortcut 与底层 helper 的真实能力一致 |
这一组文件的核心优化是:把 profile、错误和生命周期从“隐式全局状态”变为显式上下文与类型化结果。通讯录、文档等领域若只复用 Resolver 而不复用这些基础设施,仍可能出现跨租户误操作或不可恢复错误。
19.3 Chat Runtime 与契约文件
| Go 文件 | 主要优化 | 设计价值 |
|---|---|---|
internal/shortcut/chat/identity_contract.go |
新增用户、机器人、webhook 等身份契约 | 把“谁在执行”从命令分支提升为显式类型 |
internal/shortcut/chat/im_contract.go |
新增 IM 列表、写结果与公共字段契约 | 为消息、会话和批处理提供稳定域模型 |
internal/shortcut/chat/unified_send.go |
重构统一发送的目标解析、身份路由、批量发送和能力拒绝 | 用户表达发送意图,Runtime 决定合法执行器 |
internal/shortcut/chat/batch_write.go |
统一批量写去重、成功/失败账本和未知状态 | 支持部分失败审计与安全重试 |
internal/shortcut/chat/chat_conversation.go |
增强会话列表分页、投影和完整性字段 | 单页与全量模式都返回可执行 continuation |
internal/shortcut/chat/chat_group.go |
对齐群目标、成员和群操作的输入输出 | 群名与稳定 ID 共用同一解析语义 |
internal/shortcut/chat/chat_message.go |
统一消息读取、回复及消息字段投影 | 后续回复、转发、下载使用 canonical message identity |
internal/shortcut/chat/message_export.go |
新增消息 ledger 的临时写入、校验和原子发布 | 失败时不留下伪成功的半成品文件 |
internal/shortcut/chat/resource_download.go |
对齐资源下载与安全输出流程 | 下载与导出共享工作区相对路径和原子提交原则 |
internal/shortcut/chat/file_replace.go |
非 Windows 平台使用 os.Rename 提供覆盖替换 |
保持平台默认的原子替换语义 |
internal/shortcut/chat/file_replace_windows.go |
Windows 平台使用 windows.Rename |
修复 os.Rename 无法覆盖既有目标的差异 |
internal/shortcut/chat/lark_alignment.go |
补齐创建群、回复等对齐型 Shortcut | 将常用意图封装成稳定 Golden Route |
internal/shortcut/chatmsg/chatmsg.go |
大幅增强 im.message-list.v1 投影、消息身份、引用、资源、reaction 和分页 |
隔离下游消息响应差异,为 Agent 提供稳定机器结构 |
这组文件形成了一条清晰的数据流:
Target + Identity
-> Unified Route
-> 下层调用
-> Message/Conversation Projection
-> Typed Ledger
-> Atomic Export / Resource Reference
其中 identity_contract.go、im_contract.go 和 chatmsg.go 是最值得跨领域复用的部分:前两者展示如何建立类型化边界,后者展示如何把供应商响应投影成稳定领域模型。
19.4 Smart Shortcut 与 Resolver 文件
| Go 文件 | 主要优化 | 设计价值 |
|---|---|---|
internal/shortcut/targetresolver/resolver.go |
新增统一用户/群目标解析、候选去重、精确匹配、跨页搜索和结构化歧义错误 | 消除各命令独立猜测 ID/名称的根因 |
internal/shortcut/smart/resolve.go |
将旧的局部解析逻辑收敛到共享 Resolver | 降低重复实现和规则漂移 |
internal/shortcut/smart/chat_messages.go |
重构自然群/用户目标、typed 分页、去重、结果上限与导出 | 将消息历史变为有界、可证明完整的读取流程 |
internal/shortcut/smart/group_members.go |
统一群解析、用户/机器人分桶、用户分页和稳定 ID 去重 | 对复杂成员列表公开完整性和失败信息 |
internal/shortcut/smart/at_me.go |
对齐群目标解析、消息投影与资源引用 | 特殊消息查询仍复用公共契约 |
internal/shortcut/smart/search_msg.go |
统一群与发送者自然目标解析 | 多条件搜索在远端调用前完成消歧 |
internal/shortcut/smart/dm.go |
将单聊发送收敛到统一身份和目标规则 | 避免单聊维护另一套发送实现 |
internal/shortcut/smart/send_to_group.go |
将群发送收敛到 unified send | 群名、群 ID 和身份选择走同一路由 |
internal/shortcut/smart/thread_replies.go |
对齐线程回复的消息投影和资源字段 | 线程场景不再产生独立返回结构 |
internal/shortcut/runner.go |
增强 shortcut flag、约束、隐藏兼容参数和确认处理 | Runtime metadata 能真实映射到 Cobra 行为 |
internal/shortcut/types.go |
扩展 Shortcut/Flag 类型信息 | 为 Schema 生成和 Runtime 装配提供统一源数据 |
这一层最重要的代码优化是“业务适配器变薄”。Smart 命令不再负责全部搜索、能力选择、分页和投影,而是组合共享 Resolver、contract 和执行器。这种组合方式比复制命令模板更适合通讯录和文档扩展。
19.5 Policy Go 文件
scripts/policy/multi-im-skill-chain/main.go
该文件新增了一套可执行的一致性检查器,读取意图 manifest、有效 CommandRegistry、selection hints 和 Markdown marker,验证:
- 每个关键意图是否有唯一 preferred tool;
- fallback 是否有明确 reason code;
- forbidden default 是否不会重新成为首选;
- source refs 和文档 marker 是否存在;
- typed contract 与 event handoff 参考是否漂移;
- 已退休脚本是否被重新发布;
- confirmation metadata 是否被降级。
它把“评审规则”实现成 Go 程序,能够直接加载项目真实 Registry,而不是靠文本搜索猜测命令是否存在。这种 Policy-as-Code 模式可抽象成通讯录、文档等产品共用的领域 manifest 校验器。
19.6 边界收口类生产 Go 文件逐项总结
除新增核心抽象外,PR #860 还对既有 Runtime 的关键边界做了系统收口:
| Go 文件 | 主要优化 | 整体价值 |
|---|---|---|
internal/helpers/chat.go |
为删除会话分类、清空消息增加真实 --yes 门禁;安全化示例;删除旧 hint 命令 |
补齐 Runtime confirmation truth 和 Golden Route 收口 |
internal/shortcut/chat/chat_conversation.go |
在单页退出前解析 nextCursor |
修复 #860 的 continuation 缺陷 |
internal/shortcut/chat/resource_download.go |
兼容 Windows 盘符、反斜杠和 portable .. 逃逸检查 |
将 #860 文件安全扩展到跨平台 |
internal/shortcut/runner.go |
所有 flag 类型改用 Cobra *P 注册 |
提供通用 shorthand 基础能力 |
internal/shortcut/types.go |
Flag 新增 Shorthand |
让 Runtime、Schema 和 CLI 共享短参数定义 |
internal/shortcut/smart/local_chat_validation.go |
新增时间格式、默认 page limit 和结构化本地错误辅助函数 | 将散落校验收敛为公共层 |
internal/shortcut/smart/chat_messages.go |
增加时间/页大小校验和 -o;复用默认分页函数 |
阻止无效远端调用,改善常用导出体验 |
internal/shortcut/smart/at_me.go |
校验 1~3650 天及正数 limit | 为特殊读取命令建立明确资源边界 |
internal/shortcut/smart/thread_replies.go |
校验时间格式和正数 limit | 与消息列表使用相同本地校验语义 |
internal/shortcut/smart/unread_chats.go |
校验显式 count 大于 0 | 避免负数/零值被静默当作默认值 |
internal/shortcut/smart/group_members.go |
复用统一默认 page limit | 去除重复默认值分支 |
scripts/policy/multi-im-skill-chain/main.go |
对 getwd、exit、open、Registry build/bind 增加可注入接缝 | 不改变生产行为的前提下完整覆盖失败分支 |
这组代码体现了三种“小而关键”的优化:
- 修顺序:cursor 必须先提取,再决定是否继续翻页。
- 提公共函数:时间和分页校验不在多个 Smart 命令中复制。
- 建测试接缝:只对进程/I/O 边界注入,不侵入业务逻辑。
19.7 Go 测试文件优化总结
核心架构行为测试
首先建立新能力的行为基线:
targetresolver/resolver_test.go:唯一命中、多命中、稳定 ID 和结构化候选;unified_send_resolution_test.go:身份、自然群目标、批量发送和写入前失败;chatmsg_test.go:消息身份、正文、引用、reaction、资源和分页投影;- conversation/message/group 相关测试:typed list、分页和兼容字段;
- event listen 测试:计划编译、事件映射、生命周期和清理回滚;
- failure classifier/errors 测试:JSON、人类输出和服务端诊断;
- Multi IM Policy 测试:意图路由、Reference、retired script 和 contract marker。
边界与交付证据测试
其次将测试从“新增功能验证”扩展到“边界与交付证据”:
- 将 public Shortcut Schema 覆盖固定为 265/265、Chat 固定为 97/97;
- 验证 47 个新增 Schema 项的风险分类与 Runtime gate;
- 验证确认前零调用、确认后精确一次调用;
- 覆盖 cursor 缺失、无效、停滞、page limit 和后续页失败;
- 覆盖跨页同名目标仍保持歧义;
- 覆盖 Unix/Windows 路径、symlink、原子写和 no-clobber;
- 覆盖 shorthand、alias payload 等价和本地参数失败;
- 通过
CrossPlatformCoverage测试集合证明 changed-code coverage。
测试策略可概括为:
行为测试:证明新架构“能正确工作”
交付测试:证明所有公开入口“都被发布、都受约束、所有失败边界都不会越权执行”
19.8 Go 层面的核心可复用模式
| 模式 | Go 实现方式 | 适用场景 |
|---|---|---|
| Typed Resolver | 独立 package + canonical result + structured candidates | 通讯录用户/部门、文档/空间、云盘文件 |
| Thin Adapter | Smart Shortcut 组合 Resolver、contract 和 executor | 所有自然语言 Golden Route |
| Contract Projection | 独立 projector 将 map[string]any 转为稳定 v1 envelope |
列表、搜索、事件、批处理结果 |
| Fail Closed | cursor/目标/身份不完整时停止,不猜测默认值 | 写操作和需要完整集合的读取 |
| Bounded Collector | page limit、max results、seen cursor、stable dedupe | 成员、文档块、文件、审批记录 |
| Atomic Publisher | temp file、close/check、rename、no-clobber | 导出、下载、备份和迁移 |
| Typed Confirmation | metadata 声明 + Runtime 强制 gate + 零调用测试 | 删除、覆盖、转移、权限修改 |
| Injectable Boundary | 将 getwd/open/exit/build 等边界封装为函数变量 | CLI、Policy 和后台任务的失败分支测试 |
| Policy as Code | Go 加载真实 Registry/manifest 并做语义校验 | 跨产品 Schema、Skill 和 Runtime 一致性 |
Go 文件层面的核心结论是:PR #860 同时完成“抽象公共机制”“收紧运行边界”和“补齐验证证据”。复用到其他领域时,应优先复制 package 边界、类型契约和测试不变量,而不是复制具体命令函数。
20. 当前 #860 的整体价值与跨场景复用
20.1 从“运行时能力”到“可交付产品能力”
PR #860 定义了一个更完整的 Done:
| 完成层级 | 判断标准 | 对应 PR |
|---|---|---|
| 能执行 | Runtime 有真实实现 | #860 |
| 行为稳定 | Resolver、分页、typed result/error 有契约 | #860 |
| 可发现 | Registry 和 Schema 正式发布 | #860 |
| 会选择 | selection hints 有 use/avoid 语义 | #860 |
| 执行安全 | local validation、capability 和 typed confirmation 生效 | #860 |
| 可维护 | 文档分层、生成漂移、Policy 和覆盖门禁闭环 | #860 |
因此,新领域不能把“代码合入”当成交付完成。一个通讯录或文档 Shortcut 只有同时满足上表六层,才真正适合 Agent 使用。
20.2 通讯录复用重点
在 DirectoryResolver 蓝图之上,应补充 PR #860 展示的发布治理:
- 每个 user/department Shortcut 都进入 authored Registry;
- selection hints 区分“查人”“查关注的人”“查某人最近消息”等易混意图;
- 删除、调岗、批量邀请标记为 write/high 并使用 typed confirmation;
- 手机号、邮箱格式和分页大小在本地校验;
- 联系人导出路径使用 portable workspace-relative 规则;
- completeness test 禁止公开 Shortcut 依赖长期 exclusion。
20.3 文档与云盘复用重点
在原有 DocumentTargetResolver、revision/etag 和原子导出蓝图之上,应补充:
- read、write、destructive 风险 metadata;
- 覆盖、删除、权限回收必须 typed confirmation;
- 示例默认使用 dry-run 或 plan,不直接带确认参数;
- 文档 URL、路径和目标 revision 在本地尽可能校验;
- 导出/下载同时识别 Unix 与 Windows 路径语义;
- 生成 catalog 必须能追溯到 authored Registry 和 contract Reference。
20.4 推荐的跨产品发布清单
- Runtime 已实现且有单元测试。
- 目标解析支持稳定 ID 和自然目标,并对歧义 fail closed。
- 列表返回完整性与 continuation。
- 写操作声明 effect/risk/idempotency。
- Runtime gate 与 metadata 的 confirmation 完全一致。
- Registry 有 canonical path。
- Selection hints 有 use/avoid/source refs。
- Schema 和 Agent metadata 已生成且 drift clean。
- 文档第一示例不绕过确认。
- public shortcut completeness、policy 和 changed-code coverage 通过。
21. 综合验证、剩余风险与最终结论
21.1 验证事实需要分层理解
PR #860 当前描述中记录的验证包括:
DWS_PACKAGE_VERSION=0.0.0-test go test ./internal/app -count=1DWS_PACKAGE_VERSION=0.0.0-test go test ./internal/shortcut/chat ./internal/shortcut/smart -count=1make policy- generated drift clean
- Schema compatibility 与 authoritative interface integrity 通过
- 26 products / 898 tools
- 176 个 Runtime confirmation gate
- 1,108 个 reviewed Agent examples
上述是 PR 作者提供的本地验证记录。本报告通过 GitHub 状态另行确认:head 33ceab60... 的 AI Behavior 为 success,但 PR-triggered CI workflow run #1802 已完成且结论为 failure。因此不能把 PR 描述中的本地验证等同于“GitHub CI 全绿”;失败原因需结合 Actions job/log 单独排查。
21.2 仍需关注的风险
- CI 未全绿:当前 PR 仍为 Open,CI run #1802 显示 failure,应追踪失败 job,确认是否为基础设施、覆盖门禁或真实回归。
- 大型生成物审查成本:5 万余行增量主要是生成物,应持续保证 authored source、hash 和 drift check 可重建。
- Skill 上下文预算:当前 Chat Skill 为 9,928 bytes,已回到 10,000 bytes 预算内,但余量仅 72 bytes,应继续把细节下沉到 Reference。
- 字段文档漂移:
results/succeeded等批处理字段仍需合同化校验。 - Shorthand 冲突:框架支持 shorthand 后,应增加每个命令内唯一性和保留字符检查。
- 确认不是幂等:39 个写命令的 idempotency 仍为
unknown;确认只能降低误触发,不能解决重试重复写入。 - 命名式覆盖标记:大量测试依赖
CrossPlatformCoverage前缀,长期可考虑用测试清单或覆盖映射替代命名耦合。
21.3 最终结论
PR #860 将“可靠执行 IM 意图”和“完整、安全、可发现地交付能力”合并为同一套工程系统。其核心方法是:
Intent First
-> Golden Route
-> Typed Target Resolver
-> Local Validation + Preflight Capability Check
-> Typed Confirmation
-> Bounded Runtime
-> Versioned Result / Error Ledger
-> Authored Registry + Selection/Metadata
-> Generated Schema / Agent Metadata
-> Policy + Drift + Coverage Gates
这条链路可以直接作为通讯录、文档、云盘、知识库等新领域的标准交付模板。最关键的认知是:Runtime 正确只是起点;只有发现、选择、安全、契约和门禁同时闭环,能力才真正完成产品化。