Skip to content

feat(session-manager): sender/mentions 搬进 hook envelope,用户输入只剩正文 - #998

Open
liuhaoyang wants to merge 2 commits into
deepcoldy:masterfrom
liuhaoyang:feat/envelope-clean-prompt
Open

feat(session-manager): sender/mentions 搬进 hook envelope,用户输入只剩正文#998
liuhaoyang wants to merge 2 commits into
deepcoldy:masterfrom
liuhaoyang:feat/envelope-clean-prompt

Conversation

@liuhaoyang

@liuhaoyang liuhaoyang commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

改了什么

#794 后续:把 <sender><mentions> 从 PTY 文本搬进 UserPromptSubmit hook 的 system-reminder,并去掉 <user_message> 外壳,让用户输入框只剩消息正文。模型经 hook envelope 仍看得到发送者与提及,--mention 决策与 A2A 归因不受影响。

  • follow-up hook 模式:envelope 从 reminder/whiteboard 扩到 reminder/whiteboard/sender/mentions;userMessage 块在 hook 模式下输出纯正文
  • opening(新话题第一条):此前完全没走 hook,现复用同一套 sidecar/claim 机制。buildNewTopicPrompt 重构为 blocks 结构(inline 输出字节不变),buildNewTopicCliInput 在 hook 模式下把 whiteboard/sender/mentions 写进 sidecar、PTY 文本只剩正文
  • 调用点传入权威 turnId + sessionBackendType:buildReservedInitialInput(主 opening 路径)、card-handler repo-selection、live-worker empty-start 首轮、worker-null refork opening(empty-start 丢 worker 后的首条真实 turn)。raw 命令冷启动的 buffered follow-up 走 raw_input IPC 延迟发送,turnId 权威流不同,暂保持 inline;queued dashboard 场景 turnId 是合成的,同样保持 inline

为什么

用户反馈输入框里 <user_message> / <sender> / <mentions> 标签是噪音。reminder/whiteboard 已在 #794 搬进 hook,这次把剩余的 per-turn 归因元数据也搬进去,输入框只剩正文。

影响面与权衡

  • 会话发现(/adopt):主防线是 collectBotmuxSessionIdentities() 按文件名(=sessionId)排除,不依赖 transcript 内容,已关闭会话不会漏进 picker。transcript 标记正则仍匹配 inline 模式与旧会话,作为跨机/丢库的兜底
  • insight 发送者归因:hook 注入内容不落 transcript,hook 模式会话的 sender/mentions 归因降级为「未知用户」(正文与 @ 仍在)。这是干净 prompt 的已知代价
  • 短正文 + priority skills 的 opening 指纹漂移:opening 是 CLI generation 首轮,worker 的 prepareSessionSkillPrompt 会把 skill catalog 追加到 prompt 尾部。sidecar 按「catalog 追加前」的 ptyText 写指纹,hook 看到的是 ptyText+catalog → 全量指纹失配 → 靠 prefix 兜底(前 30 归一字符)。当 ptyText 归一化后 ≥30 字符时 prefix 不受尾部追加影响,可靠救回;当正文 <30 字符且配了 priority skills 时,prefix 会被 catalog 头污染,该 opening 轮的 sender/mentions/whiteboard 静默丢失(fail-open,正文仍在,模型只是看不到这轮的发送者/提及)。可达条件窄(envelopeInjection=auto + 配了 priority skills + 正文很短),属 latent。根治(hook 端剥掉尾部 catalog 再算指纹)或加 guard 留 follow-up
  • 标题提取extractBotmuxLarkNativeSessionTitlePrompt?? rawContent 兜底,不受影响
  • 超限/无条件时回退 inline,行为与历史完全一致;仅 claude-code + 本地后端 + envelopeInjection=auto + hook 已装 时生效
  • 跨 CLI:仅 claude-code 走 hook 模式,其它 CLI 仍 inline,不受影响

测试

  • pnpm build 通过
  • prompt-hook-injection(含 opening 5 例:hook 模式 PTY 只剩正文 / 缺 turnId 回退 inline / off 完全 inline / envelope 为空回退 inline / skill catalog 追加后 prefix 兜底仍能 claim)
  • prompt-buildercard-handler-repo-selectresumable-session-discoverybridge-turn-queuesession-titleprompt-context-storeipc-prompt-ctx-claim-routescheduler-silent-executeinitial-user-turn-opening 等相关套件全绿(300+ 例)
  • rebase 到最新 upstream/master 后重新 build + 测试通过
  • CI build job 通过

deepcoldy#794 后续:把 <sender> 与 <mentions> 从 PTY 文本搬进 UserPromptSubmit
hook 的 system-reminder,并去掉 <user_message> 外壳,让用户输入框
只剩消息正文。模型经 hook envelope 仍看得到发送者与提及,--mention
决策与 A2A 归因不受影响。

- follow-up hook 模式:envelope 从 reminder/whiteboard 扩到
  reminder/whiteboard/sender/mentions;userMessage 块在 hook 模式下
  输出纯正文
- opening(新话题第一条):此前完全没走 hook,现复用同一套
  sidecar/claim 机制。buildNewTopicPrompt 重构为 blocks 结构
  (inline 输出字节不变),buildNewTopicCliInput 在 hook 模式下把
  whiteboard/sender/mentions 写进 sidecar、PTY 文本只剩正文
- 调用点传入权威 turnId + sessionBackendType:buildReservedInitialInput
  (主 opening 路径)、card-handler repo-selection、live-worker
  empty-start 首轮。raw 命令冷启动的 buffered follow-up 走 raw_input
  IPC 延迟发送,turnId 权威流不同,暂保持 inline

影响面与权衡:
- 会话发现(/adopt):主防线是 collectBotmuxSessionIdentities 按
  文件名(=sessionId)排除,不依赖 transcript 内容,已关闭会话不会
  漏进 picker。transcript 标记正则仍匹配 inline 模式与旧会话
- insight 发送者归因:hook 注入内容不落 transcript,hook 模式会话的
  sender/mentions 归因降级为「未知用户」(正文与 @ 仍在)
- 标题提取:extractBotmuxLarkNativeSessionTitlePrompt 有 ?? rawContent
  兜底,不受影响
- 超限/无条件时回退 inline,行为与历史完全一致

测试:prompt-hook-injection(含新增 opening 4 例)、prompt-builder、
card-handler-repo-select、resumable-session-discovery、bridge-turn-queue
等相关套件全绿
@liuhaoyang
liuhaoyang requested a review from deepcoldy as a code owner August 25, 2026 04:12
@deepcoldy

Copy link
Copy Markdown
Owner

自动评审初步意见(最终以维护者审阅为准):

整体方向认可——把 sender/mentions 搬进 hook envelope、opening 复用同一套 sidecar/claim,inline 字节不变、fallback 纪律好。但有 3 处建议修改后再合:

1. CI 红(阻断)test/scheduler-silent-execute.test.ts:563 失败。该测试走 follow-up hook 路径,断言 PTY content 仍含 <user_message>,但本 PR 在 hook 模式下剥掉了外壳,断言不再成立。prompt-hook-injection.test.ts 里的同类断言已改,这个姊妹测试漏了。修法:把 expect(content).toContain('<user_message>') 镜像成 not.toContain(本地验证后该套件 + prompt-hook-injection + prompt-builder + initial-user-turn-opening 共 140 例全绿)。

2. opening + skill catalog 的指纹漂移建议补测:opening 的 sidecar 按「catalog 追加前」的 ptyText 写指纹,但 worker 的 prepareSessionSkillPrompt 会把 skill catalog 追加到尾部(配了 priority skills 的 bot 每次 opening 都触发),hook 看到的是 ptyText+catalog → 全量指纹失配 → 靠 prefix 兜底(前 30 归一字符)。prefix 兜底在 ptyText 归一化后 ≥30 字符时可靠(多 bot 群 / 长正文都救得回),但 ptyText <30 字符时 prefix 会被 catalog 头污染,envelope 静默丢失(单 bot 群 + 无 role/summaryMemory + 短正文 + 配了 skills 时可达;fail-open,正文仍在,只是该轮 sender/mentions/whiteboard 丢失)。现网 envelopeInjection 默认 off、唯一开 auto 的 bot 没配 skills,所以是 latent 问题。建议:① 补一个「模拟 catalog 追加后仍能 claim」的测试锁住 prefix 兜底依赖;② 短 ptyText 边界至少文档化,或加 guard(normalise 后 <30 字符且 bot 有 skills 时回退 inline)。

3. 第 4 个 opening 调用点未接线daemon.ts:20487(worker-null refork opening,empty-start 丢 worker 后的首条真实用户 turn)没传 turnId/sessionBackendType,保持 inline。该路径的权威 turnId 就是 parsed.messageId(下方 forkWorker 调用与 else 分支 buildReforkCliInput 都用它),ds.session.backendType 也在 scope 内,turnId 流与已接线的 live-worker 点(:20223)完全同构。建议补上 turnId: parsed.messageId, sessionBackendType: ds.session.backendType 两行,保持「干净 prompt」UX 一致;不接也不是错(inline 是正确兜底),但 PR 描述只列了 3 处,像疏漏。

另:除这 4 个 daemon 点外,/fork(command-handler:4814)、scheduler fire(session-manager:3559)、createSession buildPrompt(:3656)、trigger-session(:1737)也是 opening 调用点,本 PR 未接线。其中 scheduler 无 sender/mentions(envelope 可能空 → 本就 inline),/forkturnId=message.messageId 可接。若故意只覆盖主 IM 路径,建议在 PR 描述里说明范围。

…ng 调用点

P0:scheduler-silent-execute.test.ts 漏改的姊妹断言。该测试走 follow-up
hook 路径(local pty + auto),原断言 PTY content 含 <user_message>,
与本 PR 核心改动(hook 模式剥掉外壳)冲突。镜像成 not.toContain。

P1:opening sidecar 指纹 vs skill catalog 追加。opening 是 CLI generation
首轮,prepareSessionSkillPrompt 会把 skill catalog 追加到 prompt 尾部,
sidecar 按追加前的 ptyText 写指纹,hook 看到的是 ptyText+catalog,全量
指纹 miss、prefix 兜底(前 30 字符不变)救回。补「模拟 catalog 追加后仍能
claim」的测试锁住这条 fallback(消息需长于 30 字符)。

P2:补齐第 4 个 opening 调用点(daemon.ts worker-null refork opening,
empty-start 丢 worker 后的首条真实用户 turn)。此前只接了 3 处,这条路径
保持 inline,UX 不一致。现传入 turnId(非 queued 时 = parsed.messageId,
与 forkWorker 权威 turnId 一致)+ sessionBackendType;queued dashboard
场景 turnId 是合成的,保持 inline。

同步更新 initial-user-turn-opening.test.ts:opening 现走 hook 模式,
sidecar 是合法 opening envelope(claim 回含 sender、不含 follow-up
reminder),PTY 内容只剩正文。HIGH-3(不写 speculative follow-up reminder
sidecar)仍满足——opening 分支用 buildNewTopicCliInput,不跑 buildReforkCliInput。
@deepcoldy

Copy link
Copy Markdown
Owner

自动评审初步意见(最终以维护者审阅为准)——针对新 commit 23a92b0 的复审:

三处意见都收到了,感谢及时修改。逐条确认(已在当前 master 上做 trial merge 实测:0 冲突、tsc 通过、相关测试套件全绿,CI 也已转绿):

  • P0(CI 红):✅ 已修。scheduler-silent-execute.test.ts 的姊妹断言镜像为 not.toContain,套件恢复绿。
  • P2(第 4 个 opening 调用点):✅ 已修且细节到位。opening 侧的 turnId 与下方 forkWorker 的权威 turnId 严格一致;queued dashboard 场景传 undefined 回退 inline,正确避免了「sidecar 写在 parsed.messageId、forkWorker 却用合成 turnId 去 claim」的错配。(一个小观察:在 openingTurn 分支里 queuedHasDurableTail 恒为 false,因为 wantsOpening 已要求 !queuedDashboardTurn——所以这个三元当前是防御性的死分支,正确无害,留着没问题。)
  • P1(catalog 追加后的指纹漂移):✅ 已补测且测试有牙(禁用 prefix 兜底分支该测试即失败)。唯一剩下的小建议:这个测试锁的是「正文 ≥30 字符」的路径;当 ptyText 归一化后 <30 字符时,prefix 会被追加的 catalog 头污染,该 opening 轮的 sender/mentions/whiteboard 会静默丢失(fail-open,正文仍在)。可达条件较窄(envelopeInjection=auto 且配了 priority skills 且正文很短),属 latent。建议在 PR 描述的「影响面与权衡」里补一句这条边界的已知代价,与已列出的 insight 归因降级同级即可;根治(hook 端剥掉尾部 catalog 再算指纹)或加 guard 可留 follow-up。

整体方向认可,P0/P2 已闭合。以上为自动评审的初步意见,是否需要补充说明或如何取舍,最终以维护者审阅为准。

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