自托管 GitHub 三审修复机器人 robomp:以 omp RPC 为内核的 Issue 自动化处理架构与实践指南
2026/9/12 6:02:02 网站建设 项目流程

自托管 GitHub 三审修复机器人 robomp:以 omp RPC 为内核的 Issue 自动化处理架构与实践指南

【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi

本指南以 oh-my-pi 仓库中 python/robomp/AGENTS.md 为主体,结合 robomp 的源码、配置、容器编排与测试,系统讲解这个自托管 GitHub 分流修复机器人(triage-and-fix bot)的完整架构:它如何把omp --mode rpc作为子进程驱动,如何从 Webhook 到修复 PR 走完一条可靠、可恢复、可审计的数据流,以及开发者如何在本仓库中配置、运行、测试与扩展它。读完本文,你将掌握 robomp 的事件路由、会话续跑、工作区沙箱、双容器信任边界与全部ROBOMP_*配置项,并能在自己的仓库中复刻这套"Issue 进来、PR 出去"的自动化闭环。

项目定位:GitHub 上的"分流-修复"自动化层

robomp(代码位于 python/robomp,README 见 python/robomp/README.md)是一个自托管的 GitHub 分流修复机器人。它把 oh-my-pi 的 CLI 编码代理ompomp --mode rpc模式作为子进程拉起,针对每一个被允许处理的仓库(allowlisted repository)中新打开的 Issue 执行如下闭环:

  1. 分类Issue(classify);
  2. 打标签(apply labels);
  3. 按分类分支处理
    • bug/documentation→ 复现(reproduce)→ 修复(fix)→ 提交 PR;
    • question→ 单条评论回答;
    • enhancement/proposal→ 一条有思考的评论;
    • invalid/duplicate→ 一条简短评论。

后续的 Issue 评论和 PR review 评论会恢复同一个 omp 会话(resume the same omp session),让 Agent 保留此前的推理上下文。编排器(orchestrator)即使在中途重启,dispatcher 也会通过每个 Issue 独立的session_diromp --continue恢复同一会话——被中断的任务从先前的推理处继续,而不是从头再来。整个编排器是一个运行在 Docker 内的单 FastAPI 进程,事件状态由 SQLite 持久化。

说明:本文中的omp即 oh-my-pi 本体提供的编码 Agent(其 RPC 服务端由omp-rpcPython 包封装,见 python/robomp/pyproject.toml 的依赖声明omp-rpc>=0.1.0)。

端到端数据流:从 Webhook 到 omp 子进程

AGENTS.md 将整体数据流概括为一条流水线:

Webhook → durable queue → async dispatcher → per-issue git worktree → omp RPC subprocess + host tools

逐环节拆解如下(与源码一一对应):

  1. POST /webhook/github— 使用GITHUB_WEBHOOK_SECRET做 HMAC-SHA256 校验(实现于 python/robomp/src/server.py 与 python/robomp/src/github_events.py 的verify_signature)。签名错误返回401——这样 GitHub 会停止重试,而不是持续轰炸 5xx。

  2. github_events.route()决定处理方式— 返回triage_issue/handle_comment/handle_pr_conversation/handle_review/handle_release_ci/cleanup_workspace/skip之一。Bot 自己产生的事件(*[bot]后缀、user.type == "Bot"、或配置的bot_login)会被丢弃;workflow_run的发布判定(release verdicts)在 Bot 账号守卫之前就被路由——因为修复推送使用的是 Bot 账号(详见 python/robomp/src/github_events.py)。

  3. db.record_event()持久化— 以X-GitHub-Delivery作为去重键执行INSERT OR IGNORE,重复投递的事件被静默忽略,端点返回202

  4. queue.WorkerPool._dispatch_loop消费队列— 在BEGIN IMMEDIATE事务下原子认领state='queued'的行,并用进程内_inflight集合(以issue_key为键)做去重。Issue 工作按 Issue 串行化,发布工作按仓库串行化(键为<repo>#release)。并发上限为ROBOMP_MAX_CONCURRENCY(默认 8)。实现见 python/robomp/src/queue.py。

  5. sandbox.SandboxManager.ensure_workspace()产出工作区— Issue 工作区位于/data/workspaces/<owner>__<repo>__<n>/repo,分支为确定性的farm/<8hex>/<slug>格式(make_branch实现于 python/robomp/src/sandbox.py,分支名由 Issue 标题哈希 + 净化后的 slug 组成)。ensure_release_workspace()则复用<owner>__<repo>__release/repo,在默认分支上使用按 tag 区分的会话。

  6. tasks.*dispatcher 组装TaskInputs并调用worker.run_task()— 以cwd=worktree、持久的session_dir、随机挑选的任务适配模型池拉起omp --mode rpc。若<session_dir>/*.jsonl已存在,则以--continue恢复(见 python/robomp/src/worker.py 的_has_prior_session_run_rpc_blocking)。

  7. 子进程内双工具面— Agent 使用 omp内置工具(read / edit / write / bash / lsp,全部限定在工作区内)与host_tools.py中的主机工具(python/robomp/src/host_tools.py,这是唯一被允许改动 GitHub 或写入审计记录的表层)。

  8. 终态落库— 成功 → 事件state='done';异常 →state='failed'并在events.last_error记录脱敏后的 traceback。无论成败,_inflight槽位都会被释放。

从源码看事件路由细节

route()是整条管线的"大脑",它最值得注意的决策逻辑包括:

  • 仓库白名单:仓库不在ROBOMP_REPO_ALLOWLIST中直接skip
  • workflow_run事件:仅在action == "completed"、release sentinel 已启用、运行分支是默认分支或v<数字>开头的 tag 分支、且 head commit 消息以ROBOMP_RELEASE_COMMIT_PREFIX(默认chore: bump version to)开头时才排队为handle_release_ci
  • Issue 事件opened/reopened触发triage_issueclosed触发cleanup_workspace(回收工作区,不消耗用户配额);
  • 评论事件:普通 Issue 评论 →handle_comment;Bot 自己的 PR 上的会话评论 →handle_pr_conversation(外来 PR 的会话评论目前被有意忽略);PR review comment →handle_review
  • PR 事件opened/reopened/ready_for_review触发 PR review(受ROBOMP_PR_REVIEW_ENABLED开关控制);closed触发清理;
  • Directive(指令)机制:维护者@bot提及(extract_mention用词边界感知的正则剥离提及)、以及ROBOMP_REVIEWER_BOTS中配置的 review bot(如 chatgpt-codex-connector)的评论,会被解析为权威指令directive,连同parse_pragmas解析出的 pragma(如model=/thinking=覆盖项)一起传给 Agent;只有仓库 OWNER 或ROBOMP_MAINTAINER_LOGINS中的账号才有directive_authorizes_impl权限(见is_implementation_authorizer)。

会话持久化与断点续跑:--continue的完整链路

robomp 最关键的可靠性设计是"一次中断、无缝续跑":

  • 每次任务在session_dir(位于工作区下.omp-session/)写入 omp 的 JSONL 会话转录;
  • 下次任何事件到达同一 Issue 时,worker._has_prior_session()检查到*.jsonl即给RpcClient追加--continue参数(python/robomp/src/worker.py);
  • 编排器重启时,db.reset_stuck_running()把遗留在running状态的行翻回queuedWorkerPool.start()重新入队(python/robomp/src/queue.py),被中断的 Agent 从转录恢复;
  • 优雅关闭(Phase B)遵循ROBOMP_SHUTDOWN_DRAIN_TIMEOUT_SECONDS(25s)排水 +ROBOMP_SHUTDOWN_KILL_TIMEOUT_SECONDS(5s)强杀的分段策略,compose 中stop_grace_period: 30s恰好覆盖两者;被关闭中断的行故意保留running,以便下次启动时自动恢复,而不是误标failed

任务还有"完成提醒"机制:当triage_issue一轮结束后,若bug/documentation分类尚未触及终态工具(gh_open_pr/mark_unable_to_reproduce/abort_task,见_TERMINAL_TRIAGE_TOOLS),驱动会向同一会话注入最多ROBOMP_TASK_COMPLETION_MAX_REMINDERS(默认 2)次"你还没开 PR,请继续"的提示;工作区残留未提交改动时也会注入dirty_state_reminder(python/robomp/src/worker.py)。

工作区沙箱与权限模型

SandboxManager(python/robomp/src/sandbox.py)负责克隆池(clone pool)与每个 Issue 的 worktree 生命周期:

  • 共享克隆池位于/data/workspaces/_pool/<owner>__<repo>/,远程相关操作(clone / fetch / push)全部走可插拔的GitTransport抽象——进程内LocalGitTransport或经 HMAC RPC 转发的ProxyGitTransport(见robomp.proxy_client);
  • 每个 Issue 一个 worktree,分支farm/<8hex>/<slug>;后续事件在同一分支上追加修改(一个 Issue 至多一个 PR);
  • 四类磁盘所有权区:工作区树(单属主,slot UID/GID)、克隆池(多 slot 共享,root:ompsetgid02770)、语言工具缓存/data/cache/{cargo,cargo-target,rustup,bun-cache}(多 slot 共享)、Agent HOME 模板/srv/agent-home(只读root:root);
  • slot 隔离:root 进程内按需创建omp-N槽位用户(UID 2001 起),Agent 子进程以user=slot_uid, group=slot_uid, extra_groups=[omp]运行,slot 回收时扫描/proc清理遗留进程(_reap_slot),防止上一个任务的残留进程观察到下一个任务;
  • 凭证脱敏:所有 git 子进程输出、日志、审计行经redact_credentials()https://user:pw@host改写为https://***@host(python/robomp/src/git_ops.py 的GitCommandError);worker._SCRUBBED_ENV_KEYS进一步保证GITHUB_TOKENGITHUB_WEBHOOK_SECRETROBOMP_REPLAY_TOKENROBOMP_GH_PROXY_HMAC_KEY绝不进入 Agent 子进程环境(python/robomp/src/worker.py);
  • 工作区缓存回收:每次任务后剥离node_modules与工作区私有 bun 缓存(ROBOMP_RECLAIM_WORKSPACE_CACHES=true),把磁盘占用上界从"打开的 Issue 数"降为"并发数"。

双容器信任边界:robomp 编排器与 gh-proxy

docker-compose.yml(python/robomp/docker-compose.yml)定义了"两个容器、一个信任边界"的部署形态:

  • robomp— FastAPI + SQLite 事件队列 +WorkerPool,在/data/workspaces/的 per-issue worktree 中运行omp。持有 HMAC 密钥,从不持有 PAT
  • gh-proxy— 位于internal: true的内部网络上的兄弟容器,持有GITHUB_TOKEN,校验 robomp 发来的 HMAC 签名请求,执行 REST 与git push,仅对api.github.com出站。

关键安全设计:

  • compose 服务故意不用env_file:,而是用每服务的显式environment:白名单,确保.env中的GITHUB_TOKEN只进入 gh-proxy 容器;
  • 编排器到 gh-proxy 的每次请求带 HMAC-SHA256 签名,±30s 时钟偏差窗口 + 常量时间比较(hmac.compare_digest);
  • gh-proxy不映射任何宿主机端口,外部网络default只用于访问api.github.com
  • git push在 gh-proxy 内通过git -c http.extraheader=…走临时进程环境变量传 token,.git/config中的 remote URL 永不含凭证;
  • GitHub 认证模式互斥_validate_proxy_or_pat(python/robomp/src/config.py)拒绝同时设置GITHUB_TOKENROBOMP_GH_PROXY_URL + ROBOMP_GH_PROXY_HMAC_KEY,也拒绝"只设 URL 不设密钥"或"两者皆空"。

配置参考:全部ROBOMP_*环境变量

配置由 python/robomp/src/config.py 的 pydantic-settingsSettings模型加载(ROBOMP_*前缀),权威清单在 python/robomp/.env.example。下表覆盖核心项及其默认值:

变量默认值作用
GITHUB_WEBHOOK_SECRET必填Webhook HMAC-SHA256 校验密钥,须与 GitHub 仓库 Webhook 配置一致
ROBOMP_BOT_LOGIN必填Bot 账号的小写裸提及句柄(生产为roboomp,不带@/[bot],启动时归一化大小写、空白与常见变体)
ROBOMP_GIT_AUTHOR_NAME/ROBOMP_GIT_AUTHOR_EMAIL必填Bot 提交的作者身份;gh_push_branch拒绝推送任何不含该身份的分支提交
ROBOMP_REPO_ALLOWLIST必填逗号分隔的owner/repo白名单
ROBOMP_MAINTAINER_LOGINS可选:除 OWNER 外可授权实现工作的维护者登录名(逗号分隔、大小写不敏感、@可选)
ROBOMP_REVIEWER_BOTS可选:其评论被当作权威指令的 Bot 登录名(无需@bot提及)
ROBOMP_GH_PROXY_URL/ROBOMP_GH_PROXY_HMAC_KEY必填(gh-proxy 模式)编排器访问 gh-proxy 的地址与共享 HMAC 密钥;openssl rand -hex 32生成
GITHUB_TOKEN必填(PAT 模式)单进程 PAT 模式;与 gh-proxy 模式互斥
ROBOMP_MODELanthropic/claude-sonnet-4-6单个模型 id 或逗号分隔的模型池,每个任务均匀随机挑选(pick_model()),id 须与挂载进容器的models.yml(即宿主~/.omp/agent/models.container.yml)匹配
ROBOMP_PROVIDER可选 provider 覆盖(传给omp --provider
ROBOMP_THINKINGhigh思考级别:off/low/medium/high(源码另支持xhigh/max
ROBOMP_MAX_CONCURRENCY8并发认领上限
ROBOMP_TASK_TIMEOUT_SECONDS2400单轮任务超时;另有ROBOMP_TASK_TIMEOUT_HARD_GRACE_SECONDS=60硬超时宽限
ROBOMP_REQUEST_TIMEOUT_SECONDS120omp RPC 单次请求超时
ROBOMP_EVENT_MAX_RETRIES3瞬时失败事件自动重试次数,退避计划ROBOMP_EVENT_RETRY_DELAYS_SECONDS=30,120,600(带 ±20% 抖动,防全群同步重放)
ROBOMP_RATE_LIMIT_WINDOW_SECONDS/_DEFAULT/_CONTRIBUTOR/_UNLIMITED3600/3/10/ 空按提交者 GitHubauthor_association分层限流;OWNER/MEMBER/COLLABORATOR 与 unlimited 名单自动豁免
ROBOMP_QUESTION_AUTOCLOSE_ENABLED/_HOURS/_SCAN_SECONDStrue/4/60question 回答后附加"👎 保持开启"提示,作者未在时限内 👎 则自动关闭为state_reason=completed;后续评论或外部关闭会同步取消排期
ROBOMP_RELEASE_SENTINEL_ENABLEDfalse默认关闭的发布哨兵(release sentinel);开启前需订阅Workflow runs事件并给 PAT 加Actions: Read
ROBOMP_RELEASE_COMMIT_PREFIXchore: bump version to识别发布提交的前缀
ROBOMP_RELEASE_MAX_ROUNDS5修复轮次上限;ROBOMP_RELEASE_TASK_TIMEOUT_SECONDS=3600控制每轮;可选ROBOMP_RELEASE_MODEL独立选择发布模型池,否则回落到ROBOMP_MODEL
ROBOMP_PR_REVIEW_ENABLEDtrue是否启用 PR review
ROBOMP_ISSUE_INDEX_SYNC_SECONDS900本地 Issue/PR 搜索索引(SQLite FTS 镜像)的 GitHub 周期调和间隔;<=0关闭调和器
ROBOMP_NATIVES_CACHE_ENABLEDtruepi-natives 构建产物硬链接缓存(按 git tree-hash 键控),避免每个工作区重复编译
ROBOMP_RECLAIM_WORKSPACE_CACHEStrue每任务后回收依赖缓存
ROBOMP_SHUTDOWN_DRAIN_TIMEOUT_SECONDS/_KILL_TIMEOUT_SECONDS25/5优雅关闭排水/强杀窗口,两者之和必须低于 composestop_grace_period
ROBOMP_OMP_COMMANDomp容器内 omp 可执行文件(镜像自带/usr/local/bin/ompshim)
ROBOMP_WORKSPACE_ROOT/_SQLITE_PATH/_LOG_DIR/data/workspaces//data/robomp.sqlite//data/logs容器内固定路径
ROBOMP_BIND_HOST/ROBOMP_BIND_PORT0.0.0.0/8080Webhook 接收地址
ROBOMP_REPLAY_TOKEN可选:启用POST /replay的令牌,留空禁用

调试提示:.env同时被两种方式读取——docker compose${VAR}插值(配合每服务显式 allowlist),以及本地 CLI 的Settings加载器;务必二选一填写模式块。

开发命令:从源码运行到 Docker 内环

任务运行器统一为 monorepo 根 package.json 的bun配方(robomp:*命名空间),robomp 自身不再携带package.json

# 本地 venv(无需 docker) bun run robomp:install # pip install -e 'python/robomp[dev]' # 测试 bun run test:py # pytest -x python/omp-rpc/tests python/robomp/tests bun run robomp:test:integration # ROBOMP_INTEGRATION=1,要求 omp 在 PATH 上 # 宿主机直跑编排器 bun run robomp:serve # python -m robomp serve # Docker 内环 bun run pi:image # 构建 oh-my-pi/pi:dev(pi 变更时重建) bun run pi:run # docker run -it oh-my-pi/pi:dev(冒烟测试 shim) bun run robomp:build # pi:image(如 pi 变更)+ docker compose build bun run robomp:dev # build + up -d + 跟随日志 bun run robomp:up / robomp:down / robomp:restart / robomp:logs bun run robomp:rebuild # docker compose build --no-cache bun run robomp:reset # down -v 并删除 pi 镜像 # 前端(Vite + SolidJS,位于 python/robomp/web) bun run robomp:web:dev # vite dev server,代理到 :8080 bun run robomp:web:build # 产出 src/static/ 静态包 bun --cwd=python/robomp/web run check:types # tsc --noEmit

容器内 CLI(console scriptrobomp→ python/robomp/src/cli.py 的robomp.cli:main)没有根别名,直接调用:

docker compose --project-directory python/robomp exec robomp robomp triage owner/repo#N docker compose --project-directory python/robomp exec robomp robomp replay <delivery_id> docker compose --project-directory python/robomp exec robomp robomp status docker compose --project-directory python/robomp exec robomp robomp cleanup owner/repo#N

HTTP / sqlite / webhook 检查同样无别名:

curl http://localhost:${ROBOMP_BIND_PORT:-8080}/{healthz,readyz,events,issues} docker compose --project-directory python/robomp exec robomp sqlite3 /data/robomp.sqlite

首次部署流程(来自 python/robomp/README.md):

cp python/robomp/.env.example .env openssl rand -hex 32 # ROBOMP_GH_PROXY_HMAC_KEY openssl rand -hex 32 # GITHUB_WEBHOOK_SECRET bun run pi:image # 一次性构建 oh-my-pi/pi:dev bun run robomp:build && bun run robomp:up curl -fsS http://localhost:8080/healthz

镜像分层设计使构建失效范围可控:只改 robomp 的 Python 只触及运行时层;改 pi 源码才重建oh-my-pi/pi:dev(robomp 的 Dockerfile.robomp 通过FROM ${PI_BASE}继承,默认oh-my-pi/pi:dev,toolchain 全部来自 pi-base,本文件不重复)。PI_ROOT默认指向上级 oh-my-pi 检出(构建上下文与/work/pi只读挂载),仅在不同 checkout 时覆盖;容器内路径恒为/work/pi

代码规范与工程约定

AGENTS.md 的 "Code Conventions" 章节定义了仓库级的硬性约定(均可对照源码验证):

  • Python ≥3.11(容器为 3.12-slim),公共函数强制类型注解,默认from __future__ import annotations
  • 不可变值类型用@dataclass(slots=True, frozen=True),如github_client.IssueInfosandbox.Workspacedb.EventRow
  • 异步风格:FastAPI 处理器与queue.WorkerPool是 async;而worker.run_task必须保持同步并在工作线程中执行(omp-rpc是阻塞的),CLI 命令用asyncio.run包装;
  • 配置:pydantic-settingsSettings(python/robomp/src/config.py),统一经@cache单例get_settings()访问;测试改动 env 后必须调用reset_settings_cache()
  • 依赖注入SettingsDatabaseGitHubClientSandboxManager显式注入create_app()/WorkerPool/ToolBindings,除get_settings/get_database两个单例访问器外没有模块级全局变量;
  • 状态唯一真源是 SQLitedb.Database):eventsissuesreleasestool_calls四张表;release 行流转awaiting_ci → fixing → green → failed → superseded;内部_lock保证线程安全,BEGIN IMMEDIATE处理认领竞争;内存态只有WorkerPool_inflight
  • 错误处理:自定义异常族(GitHubErrorretry_afterGitCommandErrorInvalidIssueRefRpcCommandError),错误字符串严禁包含带凭证的 URL;
  • 日志:结构化 JSON(logging_config.JsonFormatter),logger.info("event", extra={...}),注意不要与_RESERVED键冲突,configure_logging()只配置一次;
  • 主机工具范式:每个工具由按任务构建的ToolBindings闭包组成,经_audit()写入tool_calls审计;审计只见 Agent 提供的参数,永不见内部凭证;新工具遵循"校验参数 → 调GitHubClient/SandboxManager→ 返回结构化 dict → 审计"的固定流程;
  • 命名:Python 全 snake_case,模块名单数名词,测试文件test_<module>.py,测试函数test_<action>_<condition>
  • 提示词:编辑src/prompts/*.md,变量用{{path.to.field}},解析在persona._lookup;提示词随包作为数据文件安装(pyproject.tomlpackage-data),新增提示词无需其他注册。

关键文件速查

文件职责
python/robomp/src/server.pyFastAPI 应用:/webhook/github/healthz/readyz/events/issues/releases、手动 triage/replay 端点、/仪表盘
python/robomp/src/queue.pyWorkerPooldispatcher 与_inflight串行化、重试、优雅关闭
python/robomp/src/tasks.pyIssue/PR 处理器 +handle_release_ci+cleanup_workspace
python/robomp/src/worker.py同步 omp RPC 驱动、提示词组装(经persona)、模型挑选、env 清洗
python/robomp/src/host_tools.pyIssue/PR 工具 +release_ci_status/release_job_log/release_retag/abort_task
python/robomp/src/sandbox.py克隆池 + Issue/release 工作区生命周期、slot 权限、凭证脱敏
python/robomp/src/github_client.py类型化 httpx 客户端(含 Actions、tag、GitHub Release 读取)
python/robomp/src/github_events.py路由与 HMAC 校验
python/robomp/src/db.pySQLite schema 与 events/issues/releases/tool_calls 的 DAO
python/robomp/src/config.pySettings模型与get_settings()
python/robomp/src/cli.pyClick CLI:serve/triage/replay/status/cleanup
python/robomp/src/dashboard.py/单页 HTML 仪表盘
python/robomp/pyproject.toml打包 + pytest 配置(asyncio_mode = "auto"testpaths)、Ruff 规则

发布哨兵(Release Sentinel):默认关闭的 CI 修复器

ROBOMP_RELEASE_SENTINEL_ENABLED=true时,完成的workflow_run事件驱动一个默认关闭的发布哨兵(python/robomp/src/tasks.py 的handle_release_ci):

  • 在可复用的main工作区中诊断失败的发布 CI;
  • 原子推送修复提交与既有发布 tag;
  • 在下一个 verdict 上恢复同一会话,直到每次运行与 GitHub Release 都变绿。

细节规则:只有 head commit 主题以ROBOMP_RELEASE_COMMIT_PREFIX开头、且运行分支为默认分支或v<版本>tag 的 completed 运行才参与匹配;远端 tag 已不再指向该运行 SHA 的过期事件被忽略;cancelled/skipped/neutral/ 过期运行不阻塞收尾;只有在所有运行均无阻塞性结论存在非 draft 的 GitHub Release 时才进入green。终态有意不在 GitHub 上发言——通过仪表盘 Releases 表、GET /releases?limit=Nrobomp status检查。release_retag是唯一的终端工具,负责原子推进main与 tag。

测试与质量保障

  • 框架:pytest,asyncio_mode = "auto"(python/robomp/pyproject.toml);HTTP 模拟统一用httpx.MockTransportrespx虽在 dev 依赖中但库内不使用,新测试应保持同一风格);
  • Fixtures(python/robomp/tests/conftest.py):env通过monkeypatch设置全部必需ROBOMP_*变量并前后调用reset_settings_cache()settings触发ensure_paths()db提供隔离的tmp_path/test.sqliteDatabase
  • 隔离规则:任何用monkeypatch.setenv改 env 的测试必须reset_settings_cache(),以失效@cache的单例get_settings()
  • 异步测试test_github_client.pytest_host_tools.py用后台线程中的自定义事件循环桥接同步风格测试与异步客户端;新测试优先 pytest-asyncioauto模式(async def test_*);
  • Mock 原则:绝不 patch 内部实现;HTTP 用httpx.MockTransport注入测试替身,存储用db/tmp_pathfixtures;sandbox 测试用本地真实 bare 仓库充当 upstream;
  • 集成测试:python/robomp/tests/test_worker_smoke.py 由ROBOMP_INTEGRATION=1门控(pytestmark.skipif),需要ompPATH上,默认的bun run test:py不会启用它;它会在httpx.MockTransport的 GitHub 与本地 bare 仓库之上拉起真实omp --mode rpc
  • 覆盖率预期:当前约 80 个单元测试;含控制流分支的新代码需要测试覆盖;新 host 工具至少要有一条 happy path + 一条校验失败路径(对照test_host_tools.py);断言可观察效果(DB / HTTP 请求),而非字面字符串或默认配置值。

安全态势小结

  • GITHUB_TOKEN只存在于 gh-proxy 容器;编排器若在自己的环境中看到GITHUB_TOKEN会拒绝启动(见 python/robomp/src/cli.py 的_require_proxy_mode);
  • 编排器 → gh-proxy 为 HMAC-SHA256 签名(±30s 偏差窗口、常量时间比较);
  • 坏的 webhook 签名返回401(让 GitHub 停止重试),绝不返回 5xx;
  • 推送前门禁(gh_push_branch):分支必须匹配工作区分支、工作树必须干净、origin/<default>..HEAD上每个提交都必须携带ROBOMP_GIT_AUTHOR_NAME+ROBOMP_GIT_AUTHOR_EMAIL;Agent 在git commit -m 'a\n\nb'中写死的 shell 字面\n转义会被改写为真实换行(仅消息,树/身份/日期保留);
  • 开 PR 前门禁(gh_open_pr):仓库定义了脚本时先跑bun run fix(任何 diff 并入 Agent 的 HEAD 提交,不产生独立style:噪音提交),再跑bun check,最后跑完整bun run test(1 小时预算);任一步失败都以RpcCommandError返回给 Agent 迭代,且不创建 PR;skip_checks=true可绕过三者但绕过动作会记录在tool_calls
  • gh_open_pr还强制校验 PR 正文包含## Repro/## Cause/## Fix/## Verification四个标题以及Fixes/Closes/Resolves #N引用。

常见问题排查

症状检查项
401 invalid signatureGITHUB_WEBHOOK_SECRET与仓库 Webhook 配置不一致
容器报PI_ROOT … missing容器内/work/pi挂载为空;宿主机应从python/robomp/运行 docker compose(PI_ROOT默认../..),或导出指向有效 oh-my-pi checkout 的PI_ROOT
git push: Authentication requiredBot PAT 缺 push 权限,或ROBOMP_BOT_LOGIN未对应 PAT 账号的提及句柄(生产为roboomp,不带@/[bot]
refusing to push: commit author identity mismatch存在非ROBOMP_GIT_AUTHOR_*身份的提交;错误会列出 SHA,git commit --amend --reset-author --no-edit修复
refusing to push: working tree is dirty有未提交的 Agent 编辑;或直接调用gh_open_pr(它会自动提交bun run fix的输出)
bun check failed before PR creation修复报错后重试gh_open_pr
refusing to open PR: \bun run test` failed before open PR| 仓库默认分支套件为红;修复并提交,若失败在改动前已存在可用skip_checks=true`
Failed to load pi_natives架构不符或缺 native;bun run pi:imagebun run robomp:build
No API key found for <provider>~/.omp/agent/models.container.yml挂载缺失,或 provider id 与ROBOMP_MODEL不匹配

结语

robomp 把"事件路由、会话续跑、工作区沙箱、双容器隔离、全量审计"组装成一个可自托管的 GitHub 自动化闭环,而其内部每一步——HMAC 校验、BEGIN IMMEDIATE认领、--continue恢复、slot 权限模型、host-tools 审计——都能在 oh-my-pi 仓库的源码与测试中找到对应实现。若你想让某类 Issue 在自家仓库里自动完成"分类 → 复现 → 修复 → PR",本文给出的架构拆解、配置清单与开发命令已足以支撑你完成部署与二次开发。

【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询