Remotion 仓库中的 AI 提交工作流解析:/commit扩展与 worker-prompt.md 的实现与协议
【免费下载链接】remotion🎥 Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion
导读:本文以 Remotion 仓库内的.pi/extensions/commit/worker-prompt.md为骨架,剖析这套内嵌在 Pi Coding Agent 里的「提交工作进程(commit worker)」机制——当你对维护者会话执行/commit时,扩展如何在临时会话分支上启动一个独立 worker、五步完成"识别改动 → 提交 → 创建/更新 GitHub PR"的全流程,并最终以严格的五行结果契约回传状态。读完本文,你将掌握该 worker 的任务边界、完整工作流与既有 PR 处理规则、输出协议的设计动机,以及它在 扩展入口 与 行为测试 中的源码级落地方式。
一、worker-prompt.md 在仓库中的定位
.pi/是仓库内嵌的 Pi Coding Agent 扩展目录,包含三个扩展:commit、pullfrog-monitor、vercel-deployment。其中commit扩展由三个文件组成:
| 文件 | 作用 |
|---|---|
| worker-prompt.md | worker 的系统提示词模板,定义任务边界、工作流与结果契约 |
| index.ts | 扩展的 TypeScript 实现,注册/commit命令并驱动整个 worker 生命周期 |
| index.test.ts | 基于bun:test的行为测试,验证消息排队与结果回传语义 |
从源码结构可以推断出清晰的职责分工:worker-prompt.md是写给另一个 AI 进程看的规范文本,而index.ts是围绕这份规范建立的运行时骨架——两者通过"运行期模板渲染 + 严格文本解析"耦合在一起,构成了一套机器可验证的 Agent 间通信协议。这正是本机制最有价值的设计点:worker 的输出不是自由文本,而是必须能被parseWorkerResult精确解析的固定格式(详见第五节)。
worker 运行在用户当前 Pi 会话树的**临时兄弟分支(temporary sibling branch)**上,拥有理解工作所需的完整对话上下文,但其推理过程与工具调用在任务结束后会从用户活跃会话分支中被移除;它操作的是与用户会话相同的 Git checkout 与工作区。换言之,这是一次"可隔离、可追踪、用完即弃"的委托式提交执行。
二、worker 的任务边界
worker 的职责被严格限定为一句话:
提交当前任务产生的改动,并创建或更新其 GitHub Pull Request。
同时,用户通过/commit附带的可选上下文({{userContext}}占位符)只作为背景信息辅助理解意图,文档明确要求:
- 不得将其直接照抄为 commit message 或 PR 标题;
- 措辞必须从实际改动、完整分支与对话上下文中推导,保证准确。
一个值得注意的边界约束写在「Workflow」末尾:不要为了制造一次提交而修改源文件。由仓库必需的 hooks 或prskill 产生的改动是被允许的,但在提交前必须检查这些改动。这从机制层面杜绝了"为提交而提交"的污染行为。
三、五步工作流
原文档把 worker 的推进过程定义为五个步骤,本文原样继承并逐一注解:
| 步骤 | 动作 | 说明 |
|---|---|---|
| 1 | 勘察现场 | 检查当前分支、Git status、已暂存/未暂存改动、未跟踪文件、分支提交记录、可能的 base 分支,以及当前分支是否已存在 PR |
| 2 | 区分改动归属 | 区分属于当前任务的改动与明显无关或模糊的改动;若无法安全判定应提交什么,绝不盲目暂存或提交,直接返回status: failed并附简要说明 |
| 3 | 无既有 PR 时创建 | 若尚无 PR 且有内容要发布,则通过 Pi 的 skill 机制走prskill,以该 skill 为准创建首个 PR |
| 4 | 已有 PR 时更新 | 若 PR 已存在,按下一节的既有 PR 规则执行 |
| 5 | 无改动时收尾 | 若没有任何可提交、可推送或值得更新的内容,返回status: no_changes |
这五步呈现的是一种先勘察、后判权、再执行的安全顺序:第 2 步是所有后续动作的闸门,无法归因的改动不会被强行纳入提交范围。
四、既有 Pull Request 的处理规则
当当前分支已经存在 PR 时,worker 必须先读取该 PR 的编号、URL、标题、完整 body、base 分支与 head 分支,再决定要更新什么。规则的核心精神可以概括为"授权明确、绝不重写历史、尊重人工内容":
- 授权语义:调用
/commit即视为用户授权暂存、提交并推送明确属于当前任务的改动,无需再次请求授权; - 提交信息:基于当前实际改动给出简洁的 commit message;评估 PR 标题与 body 时要通览整个分支;
- 推送纪律:正常 push,绝不 force-push、绕过 hooks、改写已发布历史或更改 PR base;
- 元数据更新:仅在标题需要变更时才走
pr-nameskill;仅当 PR 标题/body 已过时或不完整时才更新,不得为了换个说法而重写元数据; - 人工内容保护:保留有用的手工撰写内容(描述、issue 链接、reviewer 备注、checklist、截图/视频、验证细节等),只有分支证伪时才删除或重写;
- 更新通道:更新的 PR body 必须以 Markdown 文件形式放在临时目录中,不得通过 shell 参数内联传递 Markdown;不使用
gh pr edit,而是通过gh api以安全 JSON 编码的标题/body 更新 PR 元数据,并保持命令输出精简; - 失败降级:若普通 push 或 GitHub 更新被拒绝,立即停止并上报失败,而不是采取破坏性的恢复手段。
上述约束在 扩展入口 的实现中体现为:worker 会话结束后,扩展会等待 agent 空闲,再从源叶子节点会话树导航回去,把结果以自定义消息投递给用户;若过程中出现 assistant 错误、未产出结果或结果格式错误,都会走formatFailure失败路径并以 error 通知提示。
五、结果契约:严格的五行输出协议
worker 结束时必须只返回恰好五行、且值均为真实值的结果,禁止代码块、标题、多余行、占位符或格式说明。字段定义如下:
| 行 | 字段 | 取值 |
|---|---|---|
| 1 | status: | 四选一:committed/updated_pr/no_changes/failed |
| 2 | commit: | 实际的短 SHA 与 commit message,或none |
| 3 | pr: | 实际的 PR 编号、标题与 URL,或none |
| 4 | verification: | 执行过的验证命令,或Not run |
| 5 | notes: | 重要注意事项,或none |
四个状态值的语义区分同样关键:
committed:本次运行创建并推送了 commit(即便同时创建或更新了 PR,也以此为准);updated_pr:没有产生新 commit,但推送了既有 commit 或更新了 PR 元数据;no_changes:无内容可提交/推送/更新;failed:无法安全完成提交。
测试文件 index.test.ts 中给出了一个符合该契约的典型样例:
status: no_changes commit: none pr: none verification: Not run notes: none六、源码级实现剖析
6.1 命令注册与一次调用的完整时序
扩展通过pi.registerCommand('commit', {...})注册斜杠命令,其描述为Commit changes and create or update a PR. Usage: /commit [optional context]。命令处理器的执行时序可概括为:
- 若已有 worker 在运行则直接警告返回,防止重入;
- 等待当前 turn 空闲后记录
sourceLeafId(源会话叶子); - 用
buildWorkerPrompt(userContext)渲染提示词; - 以自定义消息
remotion-commit-worker-prompt(display: false、triggerTurn: true、deliverAs: 'followUp')触发 worker 会话; - 等待
agent_end事件,收集 worker 分支产生的消息; - 从消息中定位最后一条 prompt 消息,提取其后的最后一段 assistant 文本与可能的错误;
- 对文本做严格解析,再把结果投递回源叶子节点,最终以
remotion-commit-result类型消息展示给用户。
6.2 模板渲染:{{userContext}}的运行期替换
提示词模板并非直接发送,而是由 buildWorkerPrompt 读取与扩展同目录的worker-prompt.md,并执行:
return template.replaceAll('{{userContext}}', () => userContext || '(none provided)');也就是说,模板是数据注入后才是完整提示词——这正是"文档以{{userContext}}占位符保留可替换插槽"这一写法的实现基础。
6.3 严格的文本解析器
worker 返回的自由文本能否被接受,取决于 parseWorkerResult 的三重校验:
- 按换行切分后必须恰好等于 5 行(
RESULT_FIELDS长度); - 每一行必须以
字段名:前缀开头且值非空; - 第一行的 status 必须在
WORKER_STATUSES = ['committed', 'updated_pr', 'no_changes', 'failed']中。
解析成功后,displayStatus会把failed映射为失败、其余映射为成功;解析失败或内容缺失时,统一通过formatFailure生成五行status: failed的标准失败结果。这套设计保证了"无论 worker 行为多不可控,主会话收到的永远是规范结果"。
6.4 worker 运行期间的用户输入保护
输入事件处理 有一段重要逻辑:当commitWorkerRunning为真且事件不是来自扩展本身时,用户的交互消息会被排队挂起(并通知用户"消息将在 commit worker 退出后释放,当前排队 N 条"),返回action: 'handled',从而避免用户在 worker 执行中途把主会话"拐走"。
worker 结束后若成功回到源叶子节点,排队的消息会按顺序释放:第一条以普通方式发送(开启模板展开),其余以followUp方式递送(见 releaseQueuedUserMessages);若无法退出 worker 分支,则消息继续滞留并给出警告。
6.5 上下文隔离
扩展在pi.on('context')中过滤历史消息:remotion-commit-result类型永远不进上下文;remotion-commit-worker-prompt仅在 worker 运行时保留。这意味着提交过程的中间产物不会污染用户后续会话的上下文窗口,与"worker 的推理与工具调用将移出活跃分支"的文档声明互为印证。
6.6 行为测试佐证
index.test.ts 用 mock 的ExtensionAPI与ExtensionCommandContext验证了关键语义:worker 运行期间,交互消息(无论steer还是followUp)都会被handled且暂不投递、会话停留在 worker 叶子;当agent_end携带五行no_changes结果到达后,会话返回源叶子并发送remotion-commit-result;随后在agent_start时排队消息才被依次释放。这为「消息排队 — worker 隔离 — 结果回传 — 消息释放」的整条链路提供了可执行的行为基准。
七、设计要点总结
纵观整套机制,可以提炼出四条贯穿始终的设计原则:
- 契约先行的 Agent 间通信:worker 的行为规范写在文档中,而文档的格式约定(五行协议)又被实现方用代码强制校验,文档与代码互为规范与守护;
- 安全优先于完成度:改动归属存疑即失败、禁止 force-push、禁止破坏性恢复、push 被拒即停手;
- 人工内容与历史不可侵犯:保留手工 PR body、只改确实过时的元数据、用
gh api而非gh pr edit; - 主会话体验零污染:消息排队 + 上下文过滤 + 临时分支,保证一次 AI 提交流程对用户而言是"旁路执行、结果送达"。
八、适用前提与如何观察它工作
需要说明的是,这套机制不是 Remotion 对外发布的产品功能,而是维护者在仓库中内嵌的 Agent 开发基础设施:它依赖 index.ts 顶部导入的@earendil-works/pi-coding-agent扩展框架,并由 Pi 会话的 skill 机制(pr、pr-name)配合完成 PR 的创建与命名。若要体验,需要在安装了该扩展的 Pi Coding Agent 会话中、处于一个带有任务改动的临时分支上,执行:
/commit [可选上下文说明]随后即可在会话中观察到"worker 运行中、用户消息被暂时排队、结果以五行状态返回"的完整过程;对实现细节感兴趣的读者,可以对照 worker-prompt.md(规范)、index.ts(实现)与 index.test.ts(测试)三者逐行交叉阅读,这套"提示词文档 + 严格解析实现 + 行为测试"的组合,本身就是一份很好的 Agent 工作流工程化样例。
【免费下载链接】remotion🎥 Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考