feat(lark): 话题群内已接管话题默认免 @ 续话 - #885
Conversation
新增 topic-group 默认 @ 策略:话题群(chat_mode=topic)内 bot 已拥有 会话的话题,非 @ 消息也能续话;普通群仍需 @。原 always 改为显式 opt-out。 - resolveGroupMentionMode 默认由 always 改为 topic-group - 门控 ownedTopicNoMention:topic 档任意群、topic-group 档仅话题群 - alias fold-back 仅 topic/never/ambient 生效,topic-group 不在普通群免 @ - always 现可显式持久化(opt-out),dashboard 新增 topic-group 默认选项 - 更新受影响测试,新增话题群/普通群默认行为用例
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4cb73bedf0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const ownedTopicNoMention = ownsSession && !!message.thread_id && !mentionsOther | ||
| && (mentionMode === 'topic' | ||
| || (mentionMode === 'topic-group' && (await getChatMode(larkAppId, chatId)) === 'topic')); |
There was a problem hiding this comment.
Revalidate chat mode before relaxing the mention gate
When an admin converts a topic group back to a regular group within the five-minute chat-mode cache TTL, this lookup can still return the cached topic value and feed an unmentioned reply from an old thread into the bot, even though the new default promises regular groups still require @. The inverse conversion can suppress the newly intended no-@ behavior. For these real-thread messages, decideRoutingWithSource returns before calling getChatMode, so the cache is not prewarmed or revalidated as the preceding comment claims; use a fresh topology check for this gate, as the nearby conversion guards do.
AGENTS.md reference: AGENTS.md:L68-L68
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
已修复(ae2647d2):
- 缓存未预热:确认 real-thread 消息在
decideRoutingWithSource的root_id+thread_id分支提前 return,不会调用getChatMode。原注释「decideRouting 已预热缓存」有误,已更正。 - 改用 forceRefresh:
topic-group档的话题群判定改为getChatMode(..., { forceRefresh: true }),与邻近的群类型转换守卫一致,避免管理员在 TTL 内转换群类型后用旧值误放行。 - 顺带优化:对显式 @ 本 bot 的消息短路(
!explicitlyMentionedThisBot),这类消息走checkGroupMessageAccess,无需此放宽,也省一次 API 调用。
pnpm build + event-dispatcher 测试均通过。
real-thread 消息在 decideRoutingWithSource 提前返回,不会预热 chat_mode 缓存;管理员在 TTL 内把话题群转回普通群时,复用旧值会误放行非 @ 续话。 门控改用 forceRefresh 重新拉取,并对显式 @ 本 bot 的消息短路(走 checkGroupMessageAccess,无需此放宽,也省一次 API 调用)。
deepcoldy
left a comment
There was a problem hiding this comment.
复审结论:当前门控实现未发现功能性阻断;topic-group 的短路顺序、普通群 shared alias 不 fold、以及 ownsSession=false 的重锚分支均符合预期。
建议合入前补一条 stale-cache 回归测试:目前两个新增用例都用 mockGetChatMode.mockResolvedValue(...),即使删除 { forceRefresh: true } 也仍会通过,因此没有锁住 ae2647d 修复的真实退化。可让 mock 在无 forceRefresh 时返回缓存旧值 topic、在 forceRefresh: true 时返回当前值 group,断言普通群内非 @ 消息保持静默,并断言调用参数包含 { forceRefresh: true }。
本地验证:
pnpm build通过- 相关 unit:349/349 通过
- Dashboard/配置相关 unit:530/530 通过
test/chat-mode-strict.test.ts:12/12 通过test/multi-bot-group-flow.e2e.ts:7/7 通过
|
感谢这个 PR,实现质量很高——门控判据、第二个 commit 的 forceRefresh 缓存处理、以及测试覆盖都很扎实,review 下来运行时代码没有发现功能性阻断(build 通过,相关单测与多机器人 e2e 全绿)。 不过关于其中把默认值从 「话题内免 @ 续话」在多人 / 多机器人的话题里有一个固有副作用——话题里旁人的非 @ 消息、甚至人和人之间的对话,都会触发机器人插话。这正是 #336 当初把无条件放行回退掉的原因。把它设成全局默认,意味着所有没有显式配置过的现存 bot 行为都会随之改变,在多 bot 群里的打扰风险比较大。 另外想提一点:「话题内免 @」这个能力其实已经可以自助开启——dashboard 的「群聊 @ 策略」里选「仅话题内不需要 @」( 代码本身没有问题,方向也理解,只是这个默认值的取舍我们希望更保守一些。如果你后续还想在这块做优化,很欢迎继续交流 🙏 再次感谢你的贡献! |
改了什么
新增
topic-group默认 @ 策略:话题群(chat_mode=topic)内 bot 已拥有会话的话题,非 @ 消息也能续话;普通群仍需 @。原always改为显式 opt-out 档。resolveGroupMentionMode默认由always改为topic-groupownedTopicNoMention:topic档在任意群的已拥有话题内免 @;topic-group(默认)仅在话题群内免 @topic/never/ambient生效,topic-group不在普通群免 @always现可显式持久化(作为 opt-out),dashboard「群聊 @ 策略」新增topic-group默认选项为什么
新建话题的 agent 在话题内每次续话都要 @ 体验割裂。话题群内话题是聚焦上下文,bot 拥有该话题会话后,话题内消息理应直达 agent。
影响面
topic-group的固有取舍),由「消息 @ 其他成员时让位」缓解;不想要可显式配always。测试
pnpm build通过npx vitest run --project unit test/event-dispatcher.test.ts test/bot-registry-grant.test.ts test/card-prefs-auto-start.test.ts test/dashboard-bot-payload.test.ts全部通过bridge-*3 个既有失败(依赖node:sqlite,需 Node 22+,本机 Node 20),与本次改动无关Dashboard 变更
「群聊 @ 策略」下拉新增默认项「话题群内免 @(默认)」,原「都需要 @」不再是默认(变为显式 opt-out)。