logo
7
16
WeChat Login

fix: 补充 CNB_NPC_TRIGGER_CONTENT fallback,彻底修复 Issue 创建时读不到描述#69

Merged
created 1 weeks ago
main
auto/fix-issue-67-trigger-content-fallback-83d1f21b
Edit
OverviewCommits
1
Files changed
2
Attachments

问题分析

PR #68 已通过 preloadContext() + user message 注入解决了 Issue 描述读取的主要问题,但遗漏了一个关键边界场景:

遗漏场景:Issue 创建事件(无评论)

当用户创建 Issue 并 @mention NPC 时:

  • CNB_COMMENT_BODY 为空(没有评论)
  • CNB_NPC_TRIGGER_CONTENT = CNB_ISSUE_DESCRIPTION(等于 Issue 描述)

由于 src/context.ts 仅读取 CNB_COMMENT_BODY,且 src/main.ts 第 43 行有空检查 if (!ctx.commentBody.trim()),NPC 会直接退出,根本到不了 runAgent()

修复内容

1. src/context.ts — 添加 TRIGGER_CONTENT fallback

// 修复前
commentBody: env("CNB_COMMENT_BODY", "").replace(/\r/g, ""),

// 修复后:CNB_COMMENT_BODY 为空时 fallback 到 CNB_NPC_TRIGGER_CONTENT
commentBody: env("CNB_COMMENT_BODY", "").replace(/\r/g, "") || env("CNB_NPC_TRIGGER_CONTENT", "").replace(/\r/g, ""),

根据 CNB 官方文档,CNB_NPC_TRIGGER_CONTENT 是跨场景通用的环境变量,自动映射到对应触发源(Issue 描述/评论/PR 描述等)。

2. src/agent.ts — 防止 Issue 创建时描述重复

CNB_COMMENT_BODY 为空(Issue 创建事件)时,CNB_NPC_TRIGGER_CONTENTissueDetail.body 内容相同,需要避免在 user message 中重复显示。

触发场景验证

场景CNB_COMMENT_BODYCNB_NPC_TRIGGER_CONTENT行为
Issue 评论触发✅ 评论内容✅ 评论内容正常(使用 COMMENT_BODY)
Issue 创建触发❌ 空✅ Issue 描述✅ 修复后可正常读取
PR 评论触发✅ 评论内容✅ 评论内容正常(使用 COMMENT_BODY)
PR 创建触发❌ 空✅ PR 描述✅ 修复后可正常读取

Ref #67

referenced pull request
reviewed

问题: isIssueCreation 通过 !process.env.CNB_COMMENT_BODY 判断是否为 Issue 创建事件,但这个判断存在误判风险:

  1. 环境变量未设置 vs 空字符串process.env.CNB_COMMENT_BODY 在未设置时为 undefined,在设置为空字符串时为 ""!process.env.CNB_COMMENT_BODY 对两者都返回 true,但语义不同——环境变量未设置和用户发送了空评论是两回事。

  2. context.ts 的逻辑不一致:在 context.ts:79 中,commentBody 的赋值逻辑是 CNB_COMMENT_BODY || CNB_NPC_TRIGGER_CONTENT,即当 CNB_COMMENT_BODY 为空时会 fallback 到 CNB_NPC_TRIGGER_CONTENT。但 agent.ts:57 直接读 process.env.CNB_COMMENT_BODY,绕过了 ctx.commentBody 已有的 fallback 结果,导致两处逻辑判断基准不同。

  3. ctx.commentBody 已包含 fallback 值但未用于判断ctx.commentBody 经过 fallback 后可能非空(来自 CNB_NPC_TRIGGER_CONTENT),此时 isIssueCreation 仍会误判为 true
    建议统一使用 ctx.commentBody 的来源进行判断,或者更明确地使用 CNB_NPC_TRIGGER_CONTENT 来判断:

// 方案一:基于 ctx.commentBody 是否由 fallback 产生来判断
const isIssueCreation = !env('CNB_COMMENT_BODY', '');
// 其中 env 是 context.ts 中已有的辅助函数

// 方案二:直接用触发内容环境变量判断
const isIssueCreation = !process.env.CNB_COMMENT_BODY && !!process.env.CNB_NPC_TRIGGER_CONTENT;

这样可以确保只有真正是 Issue 创建事件(CNB_COMMENT_BODY 不存在且 CNB_NPC_TRIGGER_CONTENT 存在)时才进入创建分支,避免误判。

问题: commentBody 的 fallback 链 env('CNB_COMMENT_BODY', '').replace(/\r/g, '') || env('CNB_NPC_TRIGGER_CONTENT', '').replace(/\r/g, '')CNB_COMMENT_BODY 存在但只含 \r 字符时会丢失 fallback:

  • env('CNB_COMMENT_BODY', '') 返回 "\r"
  • .replace(/\r/g, '') 结果为 ""(空字符串)
  • "" || env('CNB_NPC_TRIGGER_CONTENT', ...) 会 fallback 到 CNB_NPC_TRIGGER_CONTENT

虽然这种边缘情况不太常见,但 || 运算符在空字符串时也会触发 fallback,这可能不是预期行为——如果用户确实发了一个空评论(仅含回车),语义上应该保留空字符串而非 fallback。
建议: 如果 fallback 只应在 CNB_COMMENT_BODY 完全未设置时触发,建议使用 nullish coalescing 或显式判断:

const rawCommentBody = process.env.CNB_COMMENT_BODY;
const rawTriggerContent = process.env.CNB_NPC_TRIGGER_CONTENT;
const commentBody = (rawCommentBody !== undefined && rawCommentBody !== '' 
  ? rawCommentBody 
  : rawTriggerContent || '').replace(/\r/g, '');

如果当前逻辑(空字符串也 fallback)是预期行为,建议添加注释说明。

问题: 当 isIssueCreationtrue 时,userMessage 仅设为 issueContext,不包含 ctx.commentBody。但此时 ctx.commentBody 已通过 context.ts:79 的 fallback 包含了 CNB_NPC_TRIGGER_CONTENT 的内容,而 issueContext 中的 d.body(来自 API)也可能包含相同的 Issue 描述。

虽然注释说「避免重复显示」,但如果 API 返回的 d.bodyCNB_NPC_TRIGGER_CONTENT 内容不完全一致(如格式化差异、截断),LLM 可能收到不一致的信息。
建议: 这是一个信息一致性的考量点。如果 d.bodyCNB_NPC_TRIGGER_CONTENT 始终一致,当前实现没有问题。建议添加注释说明这个假设,便于后续维护:

// Issue 创建时 ctx.commentBody(来自 CNB_NPC_TRIGGER_CONTENT)与 d.body(来自 API)内容一致
// 因此只使用 API 获取的 issueDetail,避免重复
userMessage = isIssueCreation ? issueContext : `${issueContext}\n\n${ctx.commentBody}`;
is using the merge method to force merge intobee9ddf4
合并来自 auto/fix-issue-67-trigger-content-fallback-83d1f21b 的合并请求 #69

Successfully merged and closed

Reviewer
(宋冬冬🦕)
Assignee
None yet
Label
None yet
Participant