Skip to content

feat(lark): 为入群开工注入群上下文 - #736

Open
hyperdai wants to merge 3 commits into
deepcoldy:masterfrom
hyperdai:codex/group-join-chat-context
Open

feat(lark): 为入群开工注入群上下文#736
hyperdai wants to merge 3 commits into
deepcoldy:masterfrom
hyperdai:codex/group-join-chat-context

Conversation

@hyperdai

@hyperdai hyperdai commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

改了什么

  • 入群自动开工复用一次 chat.get 获取群 ID、群名、群描述和群模式
  • 将群元数据作为不可信上下文注入 legacy CLI 和 Codex App,加入 XML 转义与长度限制
  • 区分元数据为空与读取失败;失败时继续开工并明确标记 unavailable
  • repo 选择和 auto-worktree 延迟启动时保留首轮群上下文

为什么

自动开工此前只能依赖群内消息,无法稳定识别仅存在于群名或群描述中的任务信息。使用机器人自身可调用的 chat.get 能避开个人 user token 依赖,并复用已有群模式查询,避免增加额外飞书请求。

影响面

  • 仅影响 autoStartOnGroupJoin 的首轮输入和对应延迟启动路径
  • 普通群、话题群以及 legacy CLI、Codex App 共用同一份群上下文语义
  • 不读取历史消息,不改变普通消息处理路径
  • 元数据按不可信输入处理,群名和群描述中的指令不会被提升为应用指令

验证

  • 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 个失败来自 Node module.register() 告警污染 CLI stderr 断言及 PTY/线程时序波动。相关文件使用 NODE_NO_WARNINGS=1 复跑后仅余 1 个线程时序用例,单独复跑该文件 11 个测试全部通过

本 PR 未切换或重启 live daemon,尚未做飞书新群入群实测。

自动开工此前只能看到群消息,无法稳定识别仅存在于群名或群描述中的任务。复用 chat.get 响应并隔离不可信元数据,避免依赖个人 user token,同时覆盖延迟选仓启动路径。
@hyperdai
hyperdai requested a review from deepcoldy as a code owner August 4, 2026 16:16

@deepcoldy deepcoldy left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审结论:🔴 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/上下文准备判断;至少补以下回归:

  1. pendingPrompt + pendingChatContext 点击 repo 选择卡,断言 fork 输入含 <chat_context>(Codex App 则断言 structured sidecar)。
  2. 同组合走 bare /repo
  3. auto-worktree 最终复用 commitRepoSelection,可用一条覆盖确认不会退化为空启动。

P3(不阻塞)

  1. fetchStatus 建议继续定为 P3,不升级。chat.get 返回 code 0 但模式为空/未知时,元数据事实上已读取成功;当前却返回 fetchStatus: unavailable,与 policy 的“元数据读取失败”文案矛盾。它不影响保守路由,也不会丢掉已读到的 name/description,所以不是 blocking。更一致的模型是 code 0 即 fetchStatus: okmode: unknown 单独表达分类失败;或者调整字段/文案明确其代表“完整上下文不可确认”。
  2. 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 passed
  • pnpm 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 都能提交同一份上下文。
@hyperdai

hyperdai commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

已按复审修复并推送 d84650b6

  • pendingChatContext 现在本身即可触发首轮构建与提交,覆盖选仓卡、bare /repo 和 auto-worktree 完成路径;空 autoStartOnGroupJoinPrompt 不再退化为空启动。
  • 同步修正 initiallyBuffered / needsPromptContext,确保准备首轮所需上下文。
  • 采纳 P3:chat.get 返回 code 0 即标记 fetchStatus=okmode=unknown 独立表示模式无法分类。
  • 新增空 prompt 回归:选仓卡(Codex App structured sidecar)、bare /repo、auto-worktree。

验证:相关 5 个测试文件共 327 个测试通过;pnpm build 通过;git diff --check 通过。未切换或重启 live daemon。

@deepcoldy deepcoldy left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

第二轮复审:🟢 fix commit 通过

基于 HEAD d84650b6e34c463d6c36e9f4108cec9fa9559090 独立复验,上一轮的 blocking 已正确修复,没有发现新的代码阻塞项。

空 prompt 延迟路径

  • command-handlerinitiallyBuffered / hasBufferedInputcard-handlerneedsPromptContext / 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 passed
  • pnpm build → passed(domain audit、tsc、dashboard bundle、build audit 均通过)
  • git diff --check → passed
  • worktree clean

仍需合并前完成(非本 fix 的代码问题)

  1. 当前 PR 对最新 origin/masterb32b71ac6)仍为 CONFLICTINGgit merge-tree 确认唯一内容冲突在 src/core/session-manager.ts,需 rebase 后同时保留 #727summaryMemoryBlock 与本 PR 的 chat context blocks;rebase 后应重新跑 build/相关测试并复核最终 diff。
  2. 按仓库规范补真实飞书新群入群 smoke(本轮 review 未 switch:here、未重启 daemon)。
  3. 等申晗确认;本轮未合码。

P3#2(模式分类重复)继续作为非阻塞后续收敛项。

群模式只用于 BotMux 内部选择 chat 或 thread 路由,模型无法消费该信息。仅向首轮输入保留群名、群描述和读取状态,使不可信业务上下文的边界更准确。
@hyperdai

hyperdai commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

按群内讨论收敛了模型侧上下文,已推送 85d50f5a

  • 从 legacy prompt 与 Codex App structured sidecar 的 <chat_context> 中移除 <chat_mode>
  • ChatContext.modechat.get 模式读取以及 daemon 的 chat/thread 路由逻辑保持不变;仅停止向模型暴露内部路由拓扑。
  • 增加 legacy 与 Codex App 断言,确保模型输入不再包含 <chat_mode>

验证:相关 5 个测试文件共 327 个测试通过;pnpm build 通过;git diff --check 通过。未切换或重启 live daemon。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants