diff --git a/docs/runbook.md b/docs/runbook.md index 8df0c94..b13dc9c 100644 --- a/docs/runbook.md +++ b/docs/runbook.md @@ -8,6 +8,7 @@ cp config/agentd.example.yaml config/agentd.local.yaml # git-ignored;或用 cli/agentd check-config # 校验 + 列出各终端 token 环境变量是否已注入 + cron 所需 --secret-env 参数 python3 -m unittest # 离线单测 ``` +调度器迁到不装 agent CLI 的 LXC:见 `docs/deploy-lxc.md`。 配置里只写 Vault 键名(`token_key`)。agentd 读同名环境变量,token 只由 `agent-access.py exec --secret-env KEY=KEY` 注入进程内存;不要 export 到 shell、不要写文件。agentd 起的所有子进程(本机 runner/执行器、win10 中继脚本)拿到的环境都去掉了全部 `token_key` 与 `webhook_secret_key` 变量。 ## 运行 @@ -28,11 +29,11 @@ crontab(oregon 实际在用,每 2 分钟): 暂停一个终端(不再派新运行、也不探测,在途运行照常收尾):把它的 `concurrency` 设为 0。 常驻替代:`... exec ... -- cli/agentd tick --loop --interval 120`(vault 会话超时要够长,cron 更稳)。 -cron 的 PATH 很短:本机执行器的二进制用终端 `bins` 写绝对路径(如 `claude: /home/ubuntu/.local/bin/claude`)。 +执行器的二进制一律用终端 `bins` 写绝对路径(如 `claude: /home/ubuntu/.local/bin/claude`):cron 和 SSH 非登录 shell 的 PATH 都只有系统目录。 ### 执行器二进制的解析(`bins` 或 PATH) 命令模板的首词(`codex`、`claude`…)若在该终端的 `bins` 里,替换为那里的绝对路径;否则**原样交给终端的 shell 按 PATH 查找**。没有任何其他探测或回退: -- oregon(local):runner 是 `bash run.sh`,环境继承 agentd 进程(cron 下 PATH 只有 `/usr/bin:/bin`),所以 `claude` 必须写进 `bins`。**示例配置的 oregon 列了 `codex` 执行器但没有 `bins.codex`,即假定 `codex` 在 PATH 上——目前 oregon 没装 codex**(`which codex` 为空),带 `exec:codex` 的 oregon 工作项会以 exit 127(`command not found`,类型=crash,非临时性)转 Waiting。要用就装 codex 并加 `bins: {codex: <绝对路径>}`,否则从 oregon 的 `executors` 去掉 codex。 +- oregon(2026-10-21 起 `warpgate-ssh`,os linux):agentd 经中继 `agent-access.py run --target oregon -- bash -c …` 在 oregon 上 `setsid nohup bash run.sh`,runner 的环境是 sshd 给 ubuntu 用户的非登录环境(PATH = 系统默认,没有 `~/.local/bin`),所以 `claude` 必须写进 `bins`。`transport: local`(runner 继承 agentd 进程环境,cron 下 PATH 只有 `/usr/bin:/bin`)仍可用于调度器与执行器同机的部署和测试。**示例配置的 oregon 列了 `codex` 执行器但没有 `bins.codex`,即假定 `codex` 在 PATH 上——目前 oregon 没装 codex**(`which codex` 为空),带 `exec:codex` 的 oregon 工作项会以 exit 127(`command not found`,类型=crash,非临时性)转 Waiting。要用就装 codex 并加 `bins: {codex: <绝对路径>}`,否则从 oregon 的 `executors` 去掉 codex。 - win10(warpgate-ssh):runner 是计划任务里的 `powershell.exe -File run.ps1`,以创建任务的用户(Administrator,交互登录)运行,PATH 取该用户的环境。示例配置用 `bins.codex` 写死 `codex.exe` 绝对路径;去掉它就等于假定 Administrator 的 PATH 里有 `codex`。 - `check-config` 不检查二进制是否存在;首次接入一个终端用 `agentd smoke ` 验证。 @@ -55,7 +56,8 @@ CLI 以 `--as ` / `agentd.cli_terminal` / 第一个有 token 的终端 | `state/agentd.log` | 每次 tick 的动作与错误 | | `state/heartbeat.json` | 最近一次 tick 的时间、在途运行、错误;超过 10 分钟不更新 = agentd 没在跑 | | `state/agentd.lock` | tick 互斥锁 | -| `state/runs//` | 本机终端的运行目录:`prompt.md run.sh pid.txt started.txt exit.txt stderr.txt` + 执行器输出 | +| `state/runs//` | `transport: local` 终端的运行目录:`prompt.md run.sh pid.txt started.txt exit.txt stderr.txt` + 执行器输出 | +| oregon `/home/ubuntu/.gwent-board/agentd-runs//` | 远程 Linux 终端(`run_root`):同上,另有 `launch.pid`(启动时的 `$!`,与 `pid.txt` 相同);claude 输出 `out.json` | | `\runtime\agentd\\`(win10) | 同上,`run.ps1`;codex 输出 `events.jsonl last.md` | ## 工作项生命周期 @@ -78,9 +80,12 @@ Todo + 指派给终端用户 → agentd 选最小编号、终端有空位、串 | `类型=env` | 匹配 `retry.env_patterns`(焦点丢失/弹窗/断网等),转 Waiting,同串行组暂停到该项离开 Waiting | | `win10 unreachable; skipping` / `busy (N codex running…)` | 中继不通,或 win10 上有不是 agentd 起的 codex(`busy_processes`);等它结束 | | `schtasks launch … failed` / `upload … failed` | 中继或 Windows 计划任务问题;手工 `win10-ps.sh "schtasks /Query /TN agentd-"` 查看 | +| `relay oregon exit 255: …` / `relay timeout` | 中继(Vault、Warpgate、目标 sshd)不通;启动失败时项留在 Todo,下一 tick 重新启动(同一 run id、目录清空重来),poll 失败下一 tick 再试。手工:`agent-access.py --config … run --target oregon --timeout 30 -- bash -c 'echo ok'` | +| `upload of … size mismatch` / `staging … size mismatch` | 远程写文件不完整(磁盘满、`run_root` 不可写);看远程 `run_root` | +| 远程 Linux 终端每步都慢 | 每次中继调用约 10–14 s(取 Vault 凭据 + SSH 握手)。一轮:启动 1 次(prompt 超过约 45 KB 时多几次分块上传)、每 tick poll 1 次、收尾 claude 约 3 次 | | 工作项在运行中被人改了状态 | 运行还没结束:下一 tick 取消(kill + `[worker] 运行已取消…` 评论),不改状态。已经结束(`exit.txt` 已写):结果照常回帖,但不再改状态/重试 | | Plane 回帖失败 | 在途记录保留,下一 tick 重新 collect 并回帖(可能重复一条评论) | -| 想手工终止一轮 | 把工作项移出 In Progress(如 Waiting)即可,下一 tick agentd 自己 kill 并释放槽位。中继不通、kill 一直失败时:在终端上手工结束(本机 `kill -TERM -`,win10 `taskkill /T /F /PID `),停 cron 后从 `state/agentd-state.json` 删掉该项的 `inflight` | +| 想手工终止一轮 | 把工作项移出 In Progress(如 Waiting)即可,下一 tick agentd 自己 kill 并释放槽位。中继不通、kill 一直失败时:在终端上手工结束(Linux 终端 `kill -TERM -- -$(cat pid.txt); pkill -TERM -s $(cat pid.txt)`,win10 `taskkill /T /F /PID `),停 cron 后从 `state/agentd-state.json` 删掉该项的 `inflight` | | `已连续 N 轮 [progress]` | 达到 `max_progress_rounds`:看最近几轮是否在原地打转;拆分任务或补充说明后移回 Todo | ## 切换记录(2026-10-21,P1-5) @@ -88,5 +93,12 @@ Todo + 指派给终端用户 → agentd 选最小编号、终端有空位、串 - 切换时旧 worker 无在途运行(GW-6 的 board-6-2 已于 06:30 以 `[blocked]` 结束,项在 Waiting)。GW-6 的 codex 线程 `01a15ce3…` 已迁入 agentd 状态(`runs=2`、`thread_on=[win10, codex]`、旧评论标为已见),移回 Todo 并指派 window10 时 agentd 续这个线程,run id 从 `GW-6-3` 起。 - 运行目录变了:旧 worker 用 win10 `runtime\board\board--`,agentd 用 `runtime\agentd\GW--`。 - 冒烟:oregon(GW-7,claude-code/sonnet,约 30 s)与 win10(GW-8,codex/gpt-6.1-sol/fast,约 3.5 min)均 PASS。win10 上验证过:`codex exec resume` 也会输出 `thread.started`(与原线程同 ID);续线程时 `-c sandbox_mode="workspace-write"` 生效,能在仓库内写文件;把运行中的项移出 In Progress 后,`taskkill /T /F /PID ` 结束了整棵树(runner powershell → codex.exe → code-mode-host / command-runner → powershell),`Get-Process codex` 归零,计划任务被删除。 -- 差异:旧 worker 对没有 model 标签的项用 sol + `service_tier="fast"`;agentd 只在有 `model:sol` 标签时加 fast,无标签项跑 sol/medium 不加 fast。需要 fast 就打 `model:sol`。 +- 差异(P1-5 时):旧 worker 对没有 model 标签的项用 sol + `service_tier="fast"`;agentd 当时只在有 `model:sol` 标签时加 fast。P1-6 起 codex 执行器有 `tier_defaults: {gpt-6.1-sol: fast}`,无标签项也是 sol + fast;`tier:` 标签改档位,`tier:none` 去掉档位参数。 - win10 上 codex 的 stderr 常见 websocket 连接被拒(`os error 10061`,`wss://chatgpt.com/...`)后回退成功;只有运行失败时它才出现在失败说明的尾部,不影响分类(不匹配临时性模式)。 + +## 切换记录(2026-10-21,P1-6:oregon 改为远程启动) +- `config/agentd.yaml` 的 oregon 从 `transport: local` 改为 `warpgate-ssh`(`target: oregon, os: linux, launch: nohup, run_root: /home/ubuntu/.gwent-board/agentd-runs`)。agentd 仍在 oregon 上跑,但启动执行器走 Warpgate 回到本机,与将来 LXC 上的路径完全相同。切换时 oregon 无在途运行;GW-7/GW-10 的 claude 线程(`thread_on=[oregon, claude-code]`)不受影响——会话存在 oregon 的 `~/.claude`,与 transport 无关。 +- win10 不变(helper 脚本 + schtasks),只是中继子进程改由共用的 `call()` 启动;切换后 GW-9 的 poll/collect 已经走新代码并正常结束。 +- 冒烟(经 Warpgate 远程启动):GW-10 第 1 轮 claude-code/sonnet PASS(`[review] ok`,启动 08:08:54 → 结束 08:10:17,session `fa3be0f7…`);评论"请回复 `[review] ok 2`"并移回 Todo 后第 2 轮续同一 session(`out.json` 的 `session_id` 不变),回 `[review] ok 2` 转 Review。启动只用 1 次中继调用(约 12 s);72 KB 的 prompt 走分块上传(约 75 s)。 +- kill:直接经中继对 oregon 起 `sleep 600 & sleep 500` 的运行再 kill,两个 sleep 都被结束(进程组 + 会话),`pid.txt` 与 `launch.pid` 相同(setsid 没有再 fork)。经 Plane 的取消冒烟(运行中移到 Waiting)因 Plane 当时 502(08:14 起)未做,待补。 +