feat(lark): 为入群开工注入群上下文 - #736
Conversation
自动开工此前只能看到群消息,无法稳定识别仅存在于群名或群描述中的任务。复用 chat.get 响应并隔离不可信元数据,避免依赖个人 user token,同时覆盖延迟选仓启动路径。
deepcoldy
left a comment
There was a problem hiding this comment.
复审结论:🔴 Request changes
整体设计(复用一次 chat.get、untrusted/application 信任切分、XML 转义和长度上限)是合理的;但延迟启动里还有一条会直接丢失本 PR 核心数据的合法路径。
[P1 / 阻塞] 空入群 prompt 经选仓或 auto-worktree 后会丢掉群上下文
autoStartOnGroupJoinPrompt 是可选配置,默认可以为空;handleBotAdded 也明确保留空 promptBody,让 agent 依靠群上下文开工。此时它会把 pendingPrompt: '' 和 pendingChatContext 一起存进 session。
但延迟提交的两条公共路径仍只用 prompt / attachment / follow-up 判断是否有首轮输入:
src/im/lark/card-handler.ts:483-520(选仓卡与 auto-worktree 最终都经commitRepoSelection)src/core/command-handler.ts:1505-1541(bare/repo)
两处 hasBufferedInput 都没有把 pendingChatContext 算进去。因此在“空 prompt + 尚无并发消息”的默认组合里,会跳过 buildNewTopicCliInput,执行 forkWorker(ds, '', false),随后清掉 pendingChatContext。结果是 CLI 只空启动,群名/群描述完全没有进入首轮;pendingTurnId 也不会作为这次首轮提交。现有新增测试都使用非空 pendingPrompt,所以 325 个测试仍会全绿。
建议让 pendingChatContext 本身足以触发 opening turn 的构建与提交,并同步处理前置 initiallyBuffered/上下文准备判断;至少补以下回归:
- 空
pendingPrompt+pendingChatContext点击 repo 选择卡,断言 fork 输入含<chat_context>(Codex App 则断言 structured sidecar)。 - 同组合走 bare
/repo。 - auto-worktree 最终复用
commitRepoSelection,可用一条覆盖确认不会退化为空启动。
P3(不阻塞)
fetchStatus建议继续定为 P3,不升级。chat.get返回 code 0 但模式为空/未知时,元数据事实上已读取成功;当前却返回fetchStatus: unavailable,与 policy 的“元数据读取失败”文案矛盾。它不影响保守路由,也不会丢掉已读到的 name/description,所以不是 blocking。更一致的模型是 code 0 即fetchStatus: ok,mode: unknown单独表达分类失败;或者调整字段/文案明确其代表“完整上下文不可确认”。chat_mode/group_message_type分类现在又复制了一份。建议抽共享分类器;getChatNameAndMode仍用chat_type判 p2p 的既存分歧可顺手收敛,但不要求本 PR 承担既存行为修复。
实际验证
pnpm vitest run test/chat-mode-strict.test.ts test/codex-app-clean-prompt.test.ts test/command-handler.test.ts test/card-handler-repo-select.test.ts test/group-join-shared-routing.test.ts→ 5 files / 325 tests passedpnpm build→ passed(domain audit、tsc、dashboard bundle、build audit 均通过)git diff --check origin/master...HEAD→ passed- 复审基于 HEAD
4424e50e1a20ff234216d32ad502a19733bed8e0
影响面判断:阻塞项位于共享 pending-repo 提交层,覆盖选仓卡、文本 /repo 与 auto-worktree,且对 legacy CLI / Codex App、PTY / tmux 后端都在 fork 前生效;普通非入群会话没有 pendingChatContext,按上述条件化处理可保持原行为。
本轮仅做 review,没有切换全局 botmux、没有重启 live daemon,也没有合码。修复并补回归后,仍建议按仓库规范补一次真实飞书拉群 smoke。
入群提示词允许为空,延迟选仓只按文本判断会把群名和群描述静默丢弃。将群上下文本身视为首轮输入,确保选仓、裸 /repo 和 auto-worktree 都能提交同一份上下文。
|
已按复审修复并推送
验证:相关 5 个测试文件共 327 个测试通过; |
deepcoldy
left a comment
There was a problem hiding this comment.
第二轮复审:🟢 fix commit 通过
基于 HEAD d84650b6e34c463d6c36e9f4108cec9fa9559090 独立复验,上一轮的 blocking 已正确修复,没有发现新的代码阻塞项。
空 prompt 延迟路径
command-handler的initiallyBuffered/hasBufferedInput与card-handler的needsPromptContext/hasBufferedInput均纳入了pendingChatContext !== undefined。- 因此空 join prompt + 有 chat context 时会进入
buildNewTopicCliInput,并携带原pendingTurnId提交真首轮;不会走forkWorker(ds, '', false)的 idle boot。 emptyStart = !pendingRawInput && !hasBufferedInput此时恒为 false,所以不会设置initialUserTurnPending;下一条业务消息仍按 follow-up 处理,不会双重开场。- 无
pendingChatContext的普通空/repo仍保持旧语义:idle boot +initialUserTurnPending=true,公共选仓行为未被改变。 - 选仓卡、bare
/repo、auto-worktree 最终都汇入这两处提交逻辑;新增回归已钉住空 prompt、context 透传、turnId 与“不置 initialUserTurnPending”。
我还用真实 buildNewTopicCliInput('', ...) 做了构造检查:legacy prompt 含 <chat_context> + 空 <user_message>;Codex App visible text 保持“主动开工(入群)”,群上下文位于 kind=untrusted 的 structured sidecar。
fetchStatus
chat.get code 0 现在统一返回 fetchStatus: ok,模式分类失败单独保留 mode: unknown;非零 code 和异常仍走 unavailable。与上一轮约定一致。
实际验证
pnpm vitest run test/chat-mode-strict.test.ts test/codex-app-clean-prompt.test.ts test/command-handler.test.ts test/card-handler-repo-select.test.ts test/group-join-shared-routing.test.ts test/initial-user-turn-opening.test.ts→ 6 files / 349 tests passedpnpm build→ passed(domain audit、tsc、dashboard bundle、build audit 均通过)git diff --check→ passed- worktree clean
仍需合并前完成(非本 fix 的代码问题)
- 当前 PR 对最新
origin/master(b32b71ac6)仍为CONFLICTING。git merge-tree确认唯一内容冲突在src/core/session-manager.ts,需 rebase 后同时保留 #727 的summaryMemoryBlock与本 PR 的 chat context blocks;rebase 后应重新跑 build/相关测试并复核最终 diff。 - 按仓库规范补真实飞书新群入群 smoke(本轮 review 未
switch:here、未重启 daemon)。 - 等申晗确认;本轮未合码。
P3#2(模式分类重复)继续作为非阻塞后续收敛项。
群模式只用于 BotMux 内部选择 chat 或 thread 路由,模型无法消费该信息。仅向首轮输入保留群名、群描述和读取状态,使不可信业务上下文的边界更准确。
|
按群内讨论收敛了模型侧上下文,已推送
验证:相关 5 个测试文件共 327 个测试通过; |
改了什么
chat.get获取群 ID、群名、群描述和群模式unavailable为什么
自动开工此前只能依赖群内消息,无法稳定识别仅存在于群名或群描述中的任务信息。使用机器人自身可调用的
chat.get能避开个人user token依赖,并复用已有群模式查询,避免增加额外飞书请求。影响面
autoStartOnGroupJoin的首轮输入和对应延迟启动路径验证
pnpm vitest run test/chat-mode-strict.test.ts test/codex-app-clean-prompt.test.ts test/command-handler.test.ts test/card-handler-repo-select.test.ts test/group-join-shared-routing.test.ts:325 个测试通过pnpm build:通过(含 domain audit 和 build audit)git diff --check:通过pnpm test:12,518 个测试通过;8 个失败来自 Nodemodule.register()告警污染 CLI stderr 断言及 PTY/线程时序波动。相关文件使用NODE_NO_WARNINGS=1复跑后仅余 1 个线程时序用例,单独复跑该文件 11 个测试全部通过本 PR 未切换或重启 live daemon,尚未做飞书新群入群实测。