深入 robomp 的 Follow-up 评论提示词:GitHub Issue 自动修复工作流的「第二次握手」决策引擎

深入 robomp 的 Follow-up 评论提示词:GitHub Issue 自动修复工作流的「第二次握手」决策引擎 深入 robomp 的 Follow-up 评论提示词GitHub Issue 自动修复工作流的「第二次握手」决策引擎【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi本文基于 python/robomp/src/prompts/followup_comment.md 展开。它不是一个普通文档而是 robomp——一个接入 Issue/PR 自动修复的 GitHub Agent 编排器——在处理已分诊线程上的后续评论维护者追加反馈、PR 变更请求、驳回意见等时注入模型的核心提示词模板。读完本文你将理解该模板的每个占位符如何被源码渲染填充、动作决策树如何在 worker 中触发、以及它如何用一组硬约束守住「绝不重复建 PR、绝不越权提交、绝不重启会话」的自动化底线。robomp 是 oh-my-pi 仓库python/robomp/目录下的自动化运维 Agent它监听 GitHub webhook把新 issue、PR 评论、release CI 结果分诊成可执行任务再驱动 coding-agent 在沙箱工作区里完成「复现 → 修复 → 开 PR」的闭环。而followup_comment.md负责的是闭环中最容易出错的一环——对话的第二次及以后一个 issue 已经有了历史线程和进行中的修复此时任何新评论都可能是维护者的新指令、驳回意见或无关提问模板必须让 Agent 在不丢失上下文的前提下精准路由动作。一、模板的定位prompts 家族中的「跟进」角色先看 python/robomp/src/prompts/ 目录全貌followup_comment.md并非孤立存在而是与一组功能互补的模板协同模板触发场景kickoff_issue.md全新 issue 的首次分诊新会话需要先 classifykickoff_directive.md维护者 提名的未分诊 issuedirective.md已分诊线程上的维护者权威指令binding覆盖原计划followup_comment.md已分诊线程上的普通跟进评论本文主角followup_review.md已开 PR 上的评审评论跟进kickoff_release.md/followup_release.mdrelease CI 任务的新建 / 续跑resume_triage.md恢复被暂停的分诊会话从文件命名规律可以看出robomp 按「事件首次到达」与「同一线程再次交互」将模板分成 kickoff / followup 两大阵营。followup_comment.md正是普通评论这一事件类型的 followup 版与directive.md权威指令版共享_inbound_scope/_origin_scope等上下文注入逻辑但决策语义完全不同见下文 Action 部分。在__all__导出中persona.py 将followup_comment与directive、kickoff、followup_review等一起注册为模板渲染入口供 worker 按任务类型分派。二、模板逐段拆解占位符背后的数据来源模板全文只有 25 行但每一行都承载着明确的运行时语义。它使用类 mustache 的{{path.to.value}}占位符语法渲染引擎定义在 persona.py_PLACEHOLDER re.compile(r\{\{\s*([a-zA-Z0-9_.])\s*\}\}) def _lookup(path: str, scope: Mapping[str, Any]) - str: parts path.split(.) value: Any scope for part in parts: if isinstance(value, Mapping): value value.get(part) else: value getattr(value, part, None) if value is None: return # 缺失字段静默降级为空串绝不抛异常 if isinstance(value, (list, tuple)): return , .join(str(item) for item in value) return str(value) def render(template: str, scope: Mapping[str, Any]) - str: return _PLACEHOLDER.sub(lambda m: _lookup(m.group(1), scope), template)关键设计项目刻意不引入真正的模板引擎模块 docstring 明确说明替换规则被限制在[a-zA-Z0-9_.]字符集内任何字段缺失都返回空串而非报错——保证模板渲染零副作用、零意外注入。模板文件通过resources.files(robomp.prompts)从包内读取并做cache缓存persona.py。followup_comment的渲染函数见 persona.pydef followup_comment(*, repo, issue, comment, workspace, pr_status, pr_numberNone, thread()) - str: return render( _load(followup_comment.md), { repo: repo, issue: issue, workspace: workspace, comment: comment, thread: _render_thread(thread), state: {pr_status: pr_status}, inbound: _inbound_scope(issue, pr_number), origin: _origin_scope(issue), }, )模板中的每个占位符与数据来源对应关系如下占位符含义数据来源{{repo.full_name}}仓库全名owner/nameRepoInfogithub_client{{inbound.number}}/{{inbound.kind}}当前 webhook 落在哪个对象上PR 号 PR或 issue 号 issue_inbound_scope()见 persona.py{{origin.description}}发源描述如originating issue #N若直接在 PR 上处理则为originating issue unknown; handling this PR directly_origin_scope()见 persona.py{{state.pr_status}}当前 PR 状态快照worker 从数据库派生见下节{{thread}}历史对话全文_render_thread()渲染的 ThreadMessage 序列{{comment.author}}/{{comment.created_at}}/{{comment.body}}新评论的作者、时间、正文CommentInfo{{workspace.branch}}当前工作分支名Workspacesandbox线程渲染_render_thread_render_thread位于 persona.py 附近把不同类型的ThreadMessage归一化为 Markdown 块issue/PR 正文标记为### {author} — issue body / PR body行内评审评论会携带路径与行号锚点如### {author} — review comment on \path/to.py:L42普通评论带时间戳。正是这段「Prior conversation」被整体嵌入模板的## Prior conversation 节让 Agent 无需重新拉取历史即可恢复上下文。三、触发链路worker 如何把评论变成这个提示词followup_comment.md并非每次评论都触发。它由 worker.py 的_build_prompt在handle_comment任务类型下、且评论不是权威指令directive is None时选用。触发前的关键步骤PR 状态派生worker 先从 sqlite 数据库查issue_row按当前状态生成pr_status字符串无 PR / 未建 PR →no PR opened yet已合并 →PR #N was merged已关闭或放弃 →PR #N was closed without merge进行中 →PR #N is open该字符串会以{{state.pr_status}}形式出现在模板首行PR: \{{state.pr_status}}是 Agent 判断「该继续 push、还是该停止」的第一手依据。权威指令分流若评论被判定为维护者 directivedirective is not None则改走 directive.md其语义为 Binding; OVERRIDES prior plan or seed todos否则才落入followup_comment模板。两种模板共享同一个pr_status、thread、inbound、origin注入但 Action 语义迥异——前者允许按指令改代码并 push后者则按本节所述的严格分类路由。复用会话状态模板末行MUST reuse recorded session state. NEVER restart from scratch.不是装饰性语句。worker 通过_has_prior_session()worker.py检测 session 目录中是否已有*.jsonl转录只要存在就用--continue接续最近一次会话SessionManager.continueRecent而不是新建。这保证 Agent 在跟进评论时持有此前复现、诊断、修复的全部记忆从而兑现模板「复用已记录会话状态」的要求。四、Action 决策树五种评论的五种反应模板的核心是## Action一节。它定义了五类评论及对应行为这是整个模板的「决策引擎」新的复现信息New repro info重新执行repro_record随后跟进gh_post_comment发布结果。即复现失败/信息不足的 issue 收到补充信息后Agent 重新验证并回帖。维护者驳回Dismissal模板用非常强硬的措辞规定了终止语义——intended、not an issue、works as designed 或任何类似措辞无论多简短永久结束修复工作流——即使修复做到一半、工作已完成。此时禁止提交、禁止 push、禁止开 PR若该线程支持set_issue_labels则打上wontfix标签最多发一条简短确认然后停止。这是模板中最不可逾越的护栏一旦维护者表明意图Agent 必须放弃所有在途工作防止「我已经做完了就顺手提交」这类越权行为。PR 变更请求Change requested在{{workspace.branch}}上修改amend并且只为已打开的 PR / 已授权的实现push。两条铁律NEVER 打开第二个 PRNEVER 为未授权的 enhancement/proposal 开第一个 PR。完成后用一条简短的gh_post_comment逐条列出变更。确认或无关提问Confirmation / unrelated question只回一条gh_post_comment代码完全不动。Bot 作者或无实质内容Bot author / no actionable contentno-op不回复不动作。这一条用来抑制 review bot如chatgpt-codex-connector互相刷屏的常见事故。配合这些动作模板还约束了工具边界评论回复必须经gh_post_comment、打标签经set_issue_labels仅追加、绝不移除已有标签见 host_tools.toml严禁绕过宿主工具直接 shell out 到gh或git push——所有副作用都收敛到gh_*工具层便于审计和权限控制。五、硬约束的工程动机为什么「绝不重启」和「绝不二开 PR」把模板中的硬约束放到 robomp 的整体架构里看每一条都是在防御自动化运维中的真实事故复用会话状态跟进评论通常出现在「复现成功、修复进行中、PR 已开」的中间态。若重新开新会话Agent 会丢失已完成的修复上下文可能重复造 PR 或推翻已有改动。_has_prior_session--continue机制worker.py从机制上保证接续而非重启。不二开 PR同一 issue 生命周期内只允许存在一个 PR 是 GitHub 工作流的常识但 LLM 在长对话中容易遗忘「PR 已存在」这一事实。模板在「变更请求」分支显式重申 NEVER并把{{state.pr_status}}放在首行作为持久提醒。驳回即终止自动化 Agent 最危险的行为就是在维护者明确说「这不是问题」之后仍强行完成修复并推送。模板将驳回语义定义为「永久结束」并禁止在途提交属于最高优先级的终止条件。Bot 评论 no-opreview bot 的自动评论会触发 webhook若不拦截会造成 bot 之间无限对话循环浪费配额并污染线程。模板直接要求 no-op配合分类逻辑构成节流。gh_push_branch与gh_open_pr的skip_checks参数host_tools.toml还展示了另一层护栏默认 push 前必须跑bun run fixbun check开 PR 前还必须跑bun run test全套测试只有验证过是main上既有的、与本次改动无关的失败才允许skip_checkstrue并必须在 PR 的## Verification中书面说明绕过理由——「脏工作树检查」则在任何情况下都强制运行。六、测试验证模板的可观察行为robomp 用单元测试锁定了模板的关键契约。见 python/robomp/tests/test_persona.pydef test_followup_comment_prompt_embeds_thread_context() - None: thread ( ThreadMessage(kindpr_body, authorroboomp, bodyPR body, created_at), ThreadMessage(kindcomment, authorcan1357, bodyprior request, created_at2026-05-01T10:00:00Z), ) out persona.followup_comment( repo_Repo(), issue_Issue(), comment_Comment(bodycurrent request), workspace_Workspace(), pr_statusPR #1080 is open, pr_number1080, threadthread, ) assert Prior conversation in out assert PR body in out assert prior request in out assert current request in out测试断言了四条核心行为标题中的Prior conversation节被生成、历史消息PR 正文与旧评论被完整嵌入、新评论正文出现、以及 PR 状态字符串被注入。这从侧面验证了模板的三个关键承诺上下文不丢失、新旧信息隔离清晰## Prior conversation/## New comment两节、PR 状态对 Agent 可见。同文件中的test_directive_prompt_embeds_thread_and_directive_bodytest_persona.py则覆盖了姊妹模板directive.md确认指令模式同样内嵌线程与指令正文。七、小结一份 25 行提示词如何撑起自动化闭环的「第二次握手」followup_comment.md是 robomp 自动化闭环中最能体现工程权衡的模板结构上它把「历史Prior conversation— 增量New comment— 决策Action」三段式固化在模板中让 LLM 明确区分旧上下文与新输入避免长对话漂移数据上它依赖 persona 层精心注入的inbound/origin/state.pr_status/thread等运行时上下文而这些上下文由 worker 从数据库与 webhook 事件实时派生行为上它用决策树 硬约束驳回即终止、不二开 PR、只经gh_*工具、复用会话、Bot 评论 no-op把不可预测的自由文本评论收敛为可审计、可中止、可恢复的有限状态机。模板引擎刻意保持最小化正则占位符 缺失即空串配合cache加载与严格的gh_*工具边界整个提示词体系在 persona.py、worker.py、host_tools.toml 与 test_persona.py 之间形成了「模板 — 渲染 — 分派 — 工具 — 测试」的完整证据链。如果你要扩展 robomp 对更多评论类型的响应例如新增「维护者要求补充测试」分支改动的起点正是这份模板及其在_build_prompt中的接线点——但请记得同步更新对应测试因为模板的可观察行为已被测试锁定。/DSMLparameter /DSMLinvoke /DSMLtool_calls【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考