Files
codex-app-server/docs/thread-wait-ops.md
T
host 755029f220 feat: 线程等待与状态读取 8 项(wait/read/message/handoff/worktree/pr-checks/automation/sleep)
对照 Codex app:wait_threads 首变+afterCursor+8上限、
read_thread 详情摘要、send_message_to_thread 复活失败任务、
handoff 登记与上报轮询、worktree 派生状态、PR checks JSON+
check-runs 日志与注释、automation GET/PATCH、clock.sleep
(API+host)。诚实边界见 docs/thread-wait-ops.md:无
worktree 阶段流、无 automation 变化静默、无独立测试结果
记录、handoff 服务端不执行迁移、wait 仅数据库级变化检测。

三套件:cloud 940 OK(4 跳过)、host 91 OK、deploy 29 OK
2026-10-28 04:33:20 +08:00

181 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 线程等待与状态读取:与 Codex app 的对照
本批实现把 Codex app 的 8 个线程/等待类工具落到本控制面。
原则:只读的绝不写(不重跑、不批准、不合并),等待的绝不
创建任务或发指令;所有“状态”都来自已有记录(任务行、
trace、审批表、后续表、git 目录),没有的字段明说没有,
不编造。
## 三类
| 类 | 官方工具 | 本端点 | 说明 |
|---|---|---|---|
| 管理并行 Agent | wait_threads | POST /tasks/{id}/wait | 等一批线程的首个重要变化 |
| 管理并行 Agent | read_thread | GET /tasks/{id}/thread/read | 深入查看单个线程的摘要 |
| 管理并行 Agent | send_message_to_thread | POST /tasks/{id}/thread/message | 向已授权线程发后续指令 |
| 读取任务状态 | get_handoff_status | GET /tasks/{id}/handoff | 移交到另一主机后的进度 |
| 读取任务状态 | get_worktree_creation_status | GET /tasks/{id}/worktree | worktree 准备状态 |
| 读取任务状态 | read_pull_request_check_diagnostics | GET /tasks/{id}/pr/checks | PR 的 CI 诊断 |
| 持续监控/等待 | automation_update | GET/PATCH /projects/{id}/automations/{aid} | 长期自动化的查看与修改 |
| 持续监控/等待 | clock.sleep | POST /tasks/{id}/sleep,host sleep | 一次性等待后继续 |
配套:POST /tasks/{id}/handoff 与 POST /tasks/{id}/handoff/{hid}/report
是移交的登记与上报口(官方是“先发起 handoff 再轮询”,
本批把发起与上报也补齐,否则 GET 无数据可轮询)。
## 对照表
### wait_threads — POST /tasks/{id}/wait
- 入参:`task_ids`(可选,缺省取锚任务的 coordinator 子任务),
`timeout_seconds`(缺省 30,上限 120),`after_cursor`(可选)。
- 一次最多 8 个线程,超了回 400(不静默截断)。
- 只返回第一个发生重要变化的线程:完成/失败等终态、
需要用户输入(elicitation 审批)、需要审批(其它审批)、
需要继续处理(待后续消息)。变化判断按 task_ids 顺序,
不是按真实时间戳排序。
- 无变化时超时回当前进度(progress 全量 + timed_out=true)。
- `after_cursor`:上一次返回的 cursor 只含各任务的状态计数,
不含正文;带它再等时,已报过的变化不再重复报。
- 它不创建任务、不发指令,只等和收集状态。
- 诚实边界:变化检测只读数据库(任务行、审批表、后续表),
不轮询 trace 文件;跨任务顺序是调用方给的顺序。
### read_thread — GET /tasks/{id}/thread/read
- 返回:状态映射(queued→waiting,completed/merged→completed,
failed/merge-failed→failed,interrupted→interrupted)、
线程摘要、最近活动(trace 末 10 条)、改动文件(trace 里
kind=file 的路径去重,上限 50)、执行命令(kind=exec 的
命令与退出码,末 20 条)、待审批、待后续、Agent 链、
阻塞/需要决策/需要处理/需要指令的 attention 汇总。
- 线程取不到时 thread=null + note,仍回 200(与 /thread 的
409/502 不同:读摘要不该因为线程缺失而全单失败)。
- `test_results` 恒为 null + 说明:trace 里没有独立的测试
结果记录,测试只能从命令退出码与 Agent 消息里看,不编
“测试通过”。
- docker 执行器任务没有本机线程,thread=null(这是预期,
不是故障)。
### send_message_to_thread — POST /tasks/{id}/thread/message
- 入参:`body`(必填,上限 20000 字),`mode`(queued|direct,
缺省 queued)。
- 授权模型:API 侧要求 API key + 项目 create_task 权限,
并记审计 thread_message_sent;“用户在聊天里让我协调”
本身不是 API 权限,调用方必须持 key。
- 排队/运行中任务:写入 task_followups(pending),direct
模式同时追加一条直接 trace。
- 已完成/失败/中断的任务:不是 409,而是复活——用 CAS
把状态改回 queued、清空旧结果与旧错误、写入 resume_message;
若已有待复活消息或状态已变,回 409(不双重复活)。
- 已合并任务回 409:worktree 已删,应 fork 新任务而不是复活。
- 目标任务(goal/verify)回 409:目标任务不接受后续消息。
- 发给其它任务的消息需要用户明确授权;本任务内按用户指令
协调。跨项目发消息不在本端点(走 peer_messages 的
/messages,跨项目会被拒绝)。
### get_handoff_status — GET /tasks/{id}/handoff
- 移交状态:pending / accepted / running / completed / failed;
终态不可再变,同态重报只算进度更新;进度 0–100,不因
终态强制改成 100。
- 同一任务同一时间只能有一个未关闭移交,否则建移交回 409。
- 响应含 current_host 与 arrived(当前主机是否等于目标主机):
这是“到了”的证据。
- 诚实边界:服务端只登记意图与轮询上报,不执行 SSH 迁移、
不搬文件;实际迁移由目标主机的 worker 执行并回 report。
### get_worktree_creation_status — GET /tasks/{id}/worktree
- 状态:remote(worktree 在别机)/ ready(目录 + .git)/
present_no_git / creating(排队或运行中且目录未建)/
missing(终态且目录未建;已合并任务删 worktree 是设计,
不是丢失)/ unknown。
- 本机且已就绪时附带当前分支(git branch --show-current,
失败则 null,不阻塞整单)。
- 诚实边界:worktree 创建在本系统是同步的,没有可观测的
“接收对象 / 更新文件”阶段流,不编百分比。
### read_pull_request_check_diagnostics — GET /tasks/{id}/pr/checks
- 只读:不重跑检查、不批准、不合并。
- 两层取数:`gh pr checks --json`(workflow、link、description
即哪个 Action 失败与失败摘要),JSON 失败时回落制表符解析;
有仓库 + head sha 且有失败项时,再走 check-runs API 拿
失败日志原文(output.text,截 4000 字)与文件行号注释
(annotations:path / start_line / message,上限 20 条,
失败 run 上限 5 个)。
- check-runs 一层失败时不 502 整单:checks 本身已够回答
“哪个检查失败”,此时 check_runs 回 available=False + note。
- 无 PR 时 409;worktree 在别机时 409(gh 必须在 worktree
所在主机跑;诊断是只读拉取,不排队等对方 worker)。
### automation_update — GET/PATCH /projects/{id}/automations/{aid}
- GET 回定义 + 近期运行(运行取不到时 runs=[] + note,
不 502 定义本身)。
- PATCH 只接受 name / prompt / interval_seconds / repo_url,
其它键静默忽略;无可更新字段回 400;已取消的自动化
回 409(取消是终态,更新不能复活);同项目同名冲突回 400。
- 更新不重置 last_run_at:改间隔只影响下一次到期,绝不
触发一次立即运行。
- 诚实边界:“变化才通知”未实现:每次运行终态仍按现有
worker 推送通道通知,没有“与上次输出比对、无变化静默”
的抑制逻辑。
### clock.sleep — POST /tasks/{id}/sleep 与 host sleep
- API:read 权限;seconds 缺省 5,只接受 0–60 的数,超出
回 400(API 层不静默截断);睡的是调用方的等待,不暂停、
不加速、不改动任务本身;返回时重读任务状态。
- host:`host.py sleep --seconds N`,0–60,超了退出码 1;
Ctrl-C 打印已睡秒数 + interrupted=true,退出码 130。
## 10 步协调流程(映射到端点)
1. 主 Agent 明确需求、影响客户端、验收标准
→ 写进 POST /tasks 的 prompt(目标任务用 verify_command)。
2. 为 Android、iOS、macOS、Web 或后端分别派发子任务
→ POST /tasks,parent_task_id 指向主任务(coordinator)。
3. 每个子任务在独立 worktree 或明确分支中开发
→ 任务 worktree 由 worker 分配;GET /tasks/{id}/worktree 查。
4. 使用 wait_threads 等待任务完成或遇到阻塞
→ POST /tasks/{主}/wait(缺省即等 coordinator 子任务)。
5. 使用 read_thread 查看详细结果
→ GET /tasks/{子}/thread/read。
6. 对失败任务使用 send_message_to_thread 要求修复
→ POST /tasks/{子}/thread/message(失败任务会复活续跑)。
7. 汇总各客户端改动并检查共享 API、事件和数据结构
→ 各子任务的 read_thread 摘要 + result_text 人工/主 Agent 对照。
8. 运行跨客户端构建、测试和集成验证
→ 新建验证任务(或目标任务的 verify_command),再走 4–6。
9. 读取 PR 的 CI 诊断并继续修复
→ POST /tasks/{id}/pr 建 PR 后,GET /tasks/{id}/pr/checks,
失败项用 thread/message 发回修复。
10. 最后由主 Agent 汇总变更、证据和剩余风险
→ 各任务 result_text + trace + 本对照表的诚实边界。
## 派发模板(映射到 POST /tasks 字段)
- 任务:prompt 首行写清任务名与一句话目标。
- 客户端:prompt 内写明(Android / iOS / macOS / Web / 后端),
本系统没有独立的客户端字段,不要另建字段。
- 仓库:项目 repo_url(建项目时定);子任务不另设仓库。
- 基线提交:写进 prompt(如“基线 abc123”),或 environment
的分支字段;没有独立的基线字段。
- 要求:写进 prompt(复用现有组件、不新建导航页等约束)。
- 验收:写进 prompt;目标任务另用 verify_command 做自动验收。
- 返回:任务完成时 result_text + trace;read_thread 再给出
改动文件、命令与退出码、待处理项。主 Agent 按“改动文件 /
执行命令与结果 / 未解决问题”三项核对,不只看一句“已做完”。
## 未实现 / 未宣称
- worktree 创建阶段流(接收对象、更新文件百分比):无。
- automation 的“无变化静默”抑制:无。
- 测试结果独立记录:无(只有命令退出码与 Agent 消息)。
- handoff 的实际迁移执行:服务端不做,靠目标主机 worker 上报。
- wait 的 trace 级变化检测:无,只有数据库级变化。
- 自动注入身份/记忆上下文到任务:不在本批(见 identity-memory)。