背景
drive file.comments list 当前直接透传开放平台 API,返回的评论包含锚定文本已被删除/重写 的评论(飞书 UI 在文档侧栏隐藏它们,但 API 仍原样返回)。对 AI Agent 而言,这会产生"幽灵评论"——根据已不存在的引用上下文起草无意义的回复。
本 issue 提议新增一个 shortcut drive +list-comments,默认行为对齐用户在飞书 UI 看到的评论卡片。
复现
以一个 docx 为例(实际线上文档):
飞书 UI 侧栏显示 22 条未解决评论
drive file.comments list --params '{"file_token":"<token>","file_type":"docx","is_solved":false}' 返回 29 条
差异 = 7 条评论锚定原文已被改 / 删除
7 条孤立评论的两种成因
类型
例子
占比
A. 锚定文本整体被删除
"Initiate Project"、"SME 完成 KEDB 的最终更新…"
6 / 7
B. 锚定的结构化元素(sticky note 等)被删除
quote 为 [Sticky note],文档里无 <readonly-block>
1 / 7
一个微妙的反例:HTML 标签拆分锚文本
API 返回的 quote 是 由 P2 / P3 事件聚类触发:…,但 XML 正文里这段文本被加粗:由 <b>P2 / P3 事件聚类</b>触发:…。简单 strings.Contains 会误判为孤立。算法必须先剥 HTML 标签 / 解 HTML entities,再做匹配。
单一锚文本在文档多处出现
API 返回的 quote 是 已知错误(4 字短锚)。文档里 已知错误 出现 43 次,但这条评论锚定的具体位置 已被删除。仅靠"quote 在文档里有无出现"会误判为 valid。
结论 :API 没有暴露 anchor block_id,纯文本匹配在短锚 + 多处出现场景下会有假阳性。本 shortcut 接受这个限制(属保守降级),并在文档中说明。
提议
CLI 形态
# 默认:筛选=未解决 + 锚定有效,输出=含评论的回复 + reaction,顺序=按 anchor 出现顺序
lark-cli drive +list-comments --doc < docx-url-or-token>
# Opt-in 扩展
--include-orphaned # 把孤立锚的评论加回来(尾部)
--include-resolved # 加上已解决评论
--no-reactions # 关闭 reaction 拉取(节省一次接口往返)
--order=created # 切到创建时间排序(默认 anchor 出现顺序)
输出结构
复用 drive file.comments list 原响应结构,每条评论多两个派生字段:
{
"comment_id" : " ..." ,
"quote" : " ..." ,
"is_solved" : false ,
"is_whole" : false ,
"anchor_state" : " valid" | "orphaned" | "structural",
"anchor_position" : 12345 ,
"reply_list" : { "replies" : [ { ..., "reactions": [...] } ] }
}
内部流程
解析 --doc,wiki URL 复用 parseCommentDocRef / resolveCommentTarget 解包。
GET /open-apis/drive/v1/files/:file_token/comments 分页拉到底(按需带 need_reaction=true)。
POST /open-apis/docs_ai/v1/documents/:token/fetch 一次拉取正文(format=xml,详见 fix: remove unsupported docs fetch text format #1109 后 text 不可用)。
对每条评论计算 anchor_state:
is_whole=true → valid(全文评论无需锚检测)
quote == "[Sticky note]" → 检查正文是否有 <readonly-block> 元素 → 有则 structural,否则 orphaned
其它 → 用 quote 首行 + 剥 HTML 标签 / 解 entities / 归一空格的子串匹配 → valid / orphaned
按 anchor_position 排序(orphan 末尾,可丢弃)。
按 flag 过滤后输出。
MVP 范围
仅支持 docx(sheet / slides 锚是 cell / xml-id,单独工作)
不解决"短锚多处出现"的歧义(在 doc 里说明 known limitation)
为什么是新 shortcut 而非给原命令加 flag
不动 drive file.comments list 现有行为 / 输出结构,避免破坏依赖原始计数的脚本。
当前 shortcuts/drive 下唯一与评论有关的 shortcut 是 +add-comment;新增 +list-comments 为后续 +resolve-comment / +update-reply 等读改类 shortcut 建立命名 pattern。
shortcut 是飞书 / AI 双使用方的"傻瓜版"入口,智能默认(unresolved + non-orphan + 按位置 + 带回复)契合 shortcut 的设计哲学(参考 +search、+inspect 等)。
Skill 同步
落地后建议在 skills/lark-drive/SKILL.md "评论查询与统计口径" 一节中:
把 drive +list-comments 设为"读评论"任务的默认入口 ;
保留 drive file.comments list 文档供高阶 / 调试场景使用;
补充孤立锚识别的算法局限。
替代方案考虑过的
方案
否决原因
给 drive file.comments list 加 --exclude-orphaned flag
改默认会破坏脚本;只加 flag 又难推动普通用户主动使用
在 SKILL.md 加"必须先 fetch 文档交叉验证 quote"强制规则
LLM 每次手动复算,开销高 + 易跳过;其他 CLI 用户得不到收益
等 Lark Open API 暴露 is_orphaned 字段
周期长,且 API 已稳定,client-side 兜底更现实
如果方向 OK,我可以同步提 PR。
背景
drive file.comments list当前直接透传开放平台 API,返回的评论包含锚定文本已被删除/重写的评论(飞书 UI 在文档侧栏隐藏它们,但 API 仍原样返回)。对 AI Agent 而言,这会产生"幽灵评论"——根据已不存在的引用上下文起草无意义的回复。本 issue 提议新增一个 shortcut
drive +list-comments,默认行为对齐用户在飞书 UI 看到的评论卡片。复现
以一个 docx 为例(实际线上文档):
drive file.comments list --params '{"file_token":"<token>","file_type":"docx","is_solved":false}'返回 29 条7 条孤立评论的两种成因
[Sticky note],文档里无<readonly-block>一个微妙的反例:HTML 标签拆分锚文本
API 返回的 quote 是
由 P2 / P3 事件聚类触发:…,但 XML 正文里这段文本被加粗:由 <b>P2 / P3 事件聚类</b>触发:…。简单strings.Contains会误判为孤立。算法必须先剥 HTML 标签 / 解 HTML entities,再做匹配。单一锚文本在文档多处出现
API 返回的 quote 是
已知错误(4 字短锚)。文档里已知错误出现 43 次,但这条评论锚定的具体位置已被删除。仅靠"quote 在文档里有无出现"会误判为 valid。结论:API 没有暴露 anchor block_id,纯文本匹配在短锚 + 多处出现场景下会有假阳性。本 shortcut 接受这个限制(属保守降级),并在文档中说明。
提议
CLI 形态
输出结构
复用
drive file.comments list原响应结构,每条评论多两个派生字段:{ "comment_id": "...", "quote": "...", "is_solved": false, "is_whole": false, "anchor_state": "valid" | "orphaned" | "structural", "anchor_position": 12345, "reply_list": { "replies": [ { ..., "reactions": [...] } ] } }内部流程
--doc,wiki URL 复用parseCommentDocRef/resolveCommentTarget解包。GET /open-apis/drive/v1/files/:file_token/comments分页拉到底(按需带need_reaction=true)。POST /open-apis/docs_ai/v1/documents/:token/fetch一次拉取正文(format=xml,详见 fix: remove unsupported docs fetch text format #1109 后text不可用)。anchor_state:is_whole=true→valid(全文评论无需锚检测)quote == "[Sticky note]"→ 检查正文是否有<readonly-block>元素 → 有则structural,否则orphanedvalid/orphanedanchor_position排序(orphan 末尾,可丢弃)。MVP 范围
为什么是新 shortcut 而非给原命令加 flag
drive file.comments list现有行为 / 输出结构,避免破坏依赖原始计数的脚本。shortcuts/drive下唯一与评论有关的 shortcut 是+add-comment;新增+list-comments为后续+resolve-comment/+update-reply等读改类 shortcut 建立命名 pattern。+search、+inspect等)。Skill 同步
落地后建议在
skills/lark-drive/SKILL.md"评论查询与统计口径" 一节中:drive +list-comments设为"读评论"任务的默认入口;drive file.comments list文档供高阶 / 调试场景使用;替代方案考虑过的
drive file.comments list加--exclude-orphanedflagis_orphaned字段如果方向 OK,我可以同步提 PR。