对照 Codex app 第二批:GET /tasks/{id}/bindings(项目/
环境/主机/worktree/PR/附件/血缘总表)、/refs 外部引用
增删查、/worktree/archive 快照(branch/head/status/diff/
untracked 路径)与 restore(目录在才解归档、目录删了
409 附快照)、自动化 bind + heartbeat(走 thread/message
同款投递路,cron 绑定不唤醒)、移交 completed 后任务
worktree_host 跟随切换、pr/checks 响应补 head_sha、
thread/read 的 tool 条目补 server/status。
诚实边界见 docs/thread-lifecycle-align.md:已有 worktree
附加、自动化变化静默、建议器、服务端定时触发器未实现;
Memory 对位是待合的 PR #102,本批不重复实现。
三套件:cloud 948 OK(4 跳过)、host 91 OK、deploy 29 OK
215 lines
12 KiB
Markdown
215 lines
12 KiB
Markdown
# 与 Codex app 的功能对齐:15 项逐项对照
|
||
|
||
本批(feat-thread-lifecycle)之前已有 #103 的 8 项
|
||
(wait/read/message/handoff/worktree/pr-checks/automation/
|
||
sleep,见 docs/thread-wait-ops.md)。本文件逐项说明 15 项
|
||
在控制面的现状:已实现 / 本批补齐 / 待合 PR / 未实现。
|
||
“已实现”指端点真实存在且有单测,不是文档宣称。
|
||
|
||
## 1. Agent 线程管理
|
||
|
||
| 能力 | 落点 | 状态 |
|
||
|---|---|---|
|
||
| 创建独立线程 | POST /tasks | 已实现 |
|
||
| 从当前线程分叉,保留上下文 | POST /tasks/{id}/fork(终态任务;worker 调 host.py fork,分叉 thread 历史 + 拷 worktree 文件) | 已实现 |
|
||
| 继续执行暂停/空闲线程 | POST /tasks/{id}/continue(终态复活);POST /tasks/{id}/thread/message(终态 CAS 复活、进行中写后续) | 已实现 |
|
||
| 向其他线程发后续指令 | POST /tasks/{id}/thread/message;跨任务 POST /tasks/{id}/messages(peer,跨项目拒绝) | 已实现 |
|
||
| 读取状态、最近结果、历史摘要 | GET /tasks/{id}/thread/read;GET /tasks/{id}/thread?include_turns=1 | 已实现(#103) |
|
||
| 设置线程标题 | POST /tasks/{id}/thread/rename {name}(终态任务 + 本机线程) | 已实现 |
|
||
| 归档和恢复线程 | POST /tasks/{id}/thread/archive、/thread/unarchive(终态任务 + 本机线程,经 host.py CLI) | 已实现 |
|
||
| 查看主机、项目、工作目录 | GET /tasks/{id}/bindings(本批) | 本批补齐 |
|
||
|
||
注意:rename/archive/unarchive 走 `_task_thread_mutate`,
|
||
只允许终态任务且本机线程;docker 任务、进行中任务会
|
||
409/守卫拦截——这是线程正在变、快照不可信的保护,
|
||
不是缺口。归档只归档线程本身,worktree 快照见第 5 项。
|
||
|
||
## 2. 并行任务等待
|
||
|
||
wait_threads = POST /tasks/{id}/wait(#103):最多 8 个、
|
||
首个重要变化返回(完成/失败/需输入/需审批/需处理)、
|
||
超时回进度、afterCursor 只取新变化。事件等待机制,
|
||
不是固定间隔定时器;变化检测只读数据库(任务行、
|
||
审批表、后续表),不轮询 trace。
|
||
|
||
## 3. 线程状态读取
|
||
|
||
read_thread = GET /tasks/{id}/thread/read(#103):状态映射、
|
||
最近活动、改动文件、命令与退出码、待审批/待后续、
|
||
attention 汇总。本批补了一个小缺口:tool 条目原来只取
|
||
tool 名,丢了 server 与 status,现在拼成
|
||
`server/tool: status` 一行。`test_results` 仍为 null:
|
||
trace 里没有独立测试结果记录,不编“测试通过”。
|
||
|
||
## 4. 任务移交和远程主机切换
|
||
|
||
- 发起移交:POST /tasks/{id}/handoff {target_host}(#103)
|
||
- 查询进度/是否成功:GET /tasks/{id}/handoff(含 arrived)
|
||
- 对方主机上报:POST /tasks/{id}/handoff/{hid}/report
|
||
- 移交后继续发指令:POST /tasks/{id}/thread/message(与
|
||
主机无关,认领方按新主机判断)
|
||
- 本批补齐的落点:report 到 completed 时,任务的
|
||
worktree_host 改成目标主机——之前上报只改移交行,
|
||
任务行还指着旧主机,后续 /worktree、/pr/checks 会
|
||
按旧主机判断,这是真缺口,现已补上。
|
||
- 未实现:服务端不执行 SSH 迁移、不搬文件;迁移本身
|
||
由目标主机 worker 执行并回报(见 thread-wait-ops.md)。
|
||
|
||
## 5. Git Worktree 生命周期管理
|
||
|
||
| 能力 | 现状 |
|
||
|---|---|
|
||
| 创建独立 worktree | 已实现:worker 认领后同步建(host.py make_worktree,一任务一分支 host/<task>,非 git 仓库退化为目录拷贝) |
|
||
| 从指定 commit/分支/ref 创建 | 部分:任务绑 environment 时按 environment.branch 检出(environment 本身是异步创建过程,creating→ready/failed);任务直接建时一律从 HEAD 建,不接受 commit/ref 参数 |
|
||
| 将已有 worktree 附加到任务 | 未实现:worker 派发路径按任务 id 确定 worktree 目录,附加需要改派发,不在本批编一个只记关联、不被执行的“附加” |
|
||
| 查看创建进度 | GET /tasks/{id}/worktree(派生状态;创建是同步的,没有阶段流,不编百分比) |
|
||
| 恢复已归档 worktree | 本批:POST /tasks/{id}/worktree/restore(见下) |
|
||
| 归档不再需要的 worktree | 本批:POST /tasks/{id}/worktree/archive 拍快照(见下);真删目录仍是 merge/discard 的职责 |
|
||
| 保存未提交修改、未推送 commit、非忽略文件 | 本批快照记:branch、head_sha(即未推送 commit 的位置)、git status、git diff、untracked 路径清单。诚实边界:untracked 文件只记路径不拷内容,diff 只覆盖已跟踪文件;快照是证据,不是可一键还原的备份 |
|
||
| 保留 worktree 与线程的关联 | 已实现:快照行含 task_id + worktree_path;bindings 里 worktree 与任务同表返回 |
|
||
|
||
Restore 语义(不编造):目录还在时只把快照标 restored
|
||
(目录没动过,谈不上还原);目录已删时 409 并附快照
|
||
(重建需要仓库路径,服务端没有)。
|
||
|
||
## 6. 任务与 Git 状态绑定
|
||
|
||
本批 GET /tasks/{id}/bindings 一次返回:项目(名、
|
||
repo_url)、环境(名、分支、执行器、状态)、主机
|
||
(worktree_host、local/remote、本机名)、worktree
|
||
(状态、路径、分支)、分支、PR(url/number)、执行器
|
||
(任务值或全局缺省)、附件(文件 + 外部引用)、
|
||
worktree 快照清单、血缘(parent_task_id、forked_from、
|
||
coordinator_part)。之前这些字段散在任务行、项目行、
|
||
环境行、worktree 端点里,没有一张总表。
|
||
|
||
## 7. Pull Request 和 CI 诊断
|
||
|
||
read_pull_request_check_diagnostics =
|
||
GET /tasks/{id}/pr/checks(#103):checks JSON(workflow、
|
||
link、description)、失败 run 的 check-runs 日志原文
|
||
(截 4000 字)与行号注释(上限 20 条)。本批只补一个
|
||
字段:响应里加 head_sha(PR 当前 commit,之前内部
|
||
算出来只用于查 check-runs,没返回)。只读:不重跑、
|
||
不批准、不合并。外部 CI 状态即 check-runs 的
|
||
conclusion;构建/测试失败日志即 output.text。
|
||
|
||
## 8. 自动化、心跳和定时任务
|
||
|
||
| 能力 | 现状 |
|
||
|---|---|
|
||
| 创建/查看/修改/删除长期自动化 | POST/GET/PATCH /projects/{id}/automations、cancel(#103 前已有 + #103 的 update) |
|
||
| 按时间周期运行 | 已实现:interval_seconds(60 秒–30 天),到期判断 last_run + interval |
|
||
| 定期唤醒已有线程(heartbeat) | 本批:POST .../automations/{aid}/bind {task_id, mode: heartbeat} + POST .../automations/{aid}/heartbeat {message?}(缺省用自动化 prompt);投递走 thread/message 同款路(终态复活、进行中写后续、配额门同款) |
|
||
| cron(到期独立跑新任务) | 绑定 mode=cron 只作标记;heartbeat 口对 cron 绑定回 409(cron 不唤醒线程) |
|
||
| 复用已有对话上下文 | heartbeat 唤醒的是同一线程,上下文自然复用;cron 新任务不继承历史(与 fork 的语义一致) |
|
||
| 继续执行多日/多周任务 | 机制上可以(interval 上限 30 天 + 绑定线程长期存在),未做跨周的专项验证 |
|
||
| 只在变化/完成/失败/需处理时通知,状态不变保持安静 | 未实现:没有“与上次产出比对、无变化静默”的抑制逻辑;每次运行终态仍按现有推送通道通知 |
|
||
| 到期触发器 | 未实现(服务端本身不起定时器):触发需外部调 /heartbeat,或等 PR #101 的 run_due_automation 落地;本批只给了绑定与唤醒口,没宣称“已自动跑” |
|
||
|
||
## 9. 线程归档和恢复
|
||
|
||
线程归档/恢复见第 1 项(host.py CLI 透传)。归档时
|
||
保留的东西分两处:对话记录与线程状态在 codex-home
|
||
的线程存档里;worktree 快照在本批的
|
||
task_worktree_snapshots 里;PR 附件在任务行的
|
||
pr_url/pr_number 与 bindings 里;未提交文件快照即
|
||
第 5 项的快照(status/diff/untracked 路径)。长期
|
||
项目、阶段性任务、暂时暂停的 Agent 走“归档线程 +
|
||
拍 worktree 快照”两步,不是同一个端点。
|
||
|
||
## 10. 任务附件和交付物管理
|
||
|
||
- 文件:已实现——task_attachments(上传包绑定,任务行
|
||
attachments 字段,fork 时带走清单)。
|
||
- PR、worktree:已实现——任务行 pr_url/pr_number、
|
||
worktree 路径,bindings 同表返回。
|
||
- 生成的文档、构建结果、外部服务结果引用:本批——
|
||
POST/GET/DELETE /tasks/{id}/refs(kind: doc/build/
|
||
external/pr/file,只记引用不存内容、不校验链接可达)。
|
||
- 移除:refs 可 DELETE;文件附件的移除走上传包的
|
||
used 状态与任务删除,不在本批另开删除口。
|
||
|
||
## 11. 项目和主机上下文
|
||
|
||
GET /tasks/{id}/bindings 即上下文总表(项目、仓库、
|
||
主机、本地/远程、工作目录、默认执行器、环境、归属)。
|
||
项目默认执行器:任务 executor 为空时取全局缺省
|
||
(_default_executor),没有“项目级默认执行器”字段——
|
||
环境行(executor)是更细的默认,任务绑 environment
|
||
时以环境为准。
|
||
|
||
## 12. 插件、MCP 和外部连接器
|
||
|
||
已实现(经 host.py CLI 透传,项目 scope):
|
||
|
||
- GET /projects/{id}/skills(skills/list)
|
||
- GET /projects/{id}/apps(app/list)
|
||
- GET /projects/{id}/mcp-servers(mcpServerStatus/list)
|
||
- POST /projects/{id}/mcp-servers/reload
|
||
- POST /projects/{id}/mcp-servers/{name}/oauth-login
|
||
|
||
限制与官方一致:连接受账户、工作区、管理员权限、
|
||
插件安装状态限制;oauth-login 只是发起流程,真正
|
||
授权在宿主侧完成;容器内视图与宿主侧视图可能不同
|
||
(skills/MCP 端点 docstring 已注明)。GitHub、Slack
|
||
等具体外部系统在本系统是另外的连接器(GitHub App、
|
||
Slack webhook),不是 MCP 一个口。
|
||
|
||
## 13. Memory 和长期上下文
|
||
|
||
分两层,不要混淆:
|
||
|
||
- 已实现(本系统自有):KB(/projects/{id}/kb)与
|
||
任务 summaries——按任务/项目存的背景,不是跨任务
|
||
的用户长期记忆。
|
||
- 待合 PR:PR #102(feat-cloud-memory-identity,
|
||
user_profiles + identity_memories,用户级仅本人、
|
||
项目级项目成员可见,上下文各取最新 5 条)——
|
||
这才是官方 Memory 的对位。本批不重复实现,避免
|
||
与 #102 合并冲突;自动注入任务/thread 是 #102
|
||
之后仍待显式决策的下一步(注入点、去重、成本上限)。
|
||
- 可用性限制与官方一致:记忆的范围受账户与发布状态
|
||
影响,本系统里受项目成员权限限制。
|
||
|
||
## 14. 主动续作和建议性任务
|
||
|
||
未实现为独立服务。现有拼图:自动化(到期唤醒/独立
|
||
跑)+ triage(/projects/{id}/triage,自动化到期与
|
||
待处理汇总)+ #102 的记忆 + bindings 的 PR/任务状态。
|
||
“根据未完成任务、关联 PR、插件内容、Memory、项目
|
||
上下文建议下一步”需要一个建议器(读上述输入、产出
|
||
建议任务),不在本批范围;本批的 heartbeat 与
|
||
bindings 是给建议器准备的输入口与执行口,不是建议器
|
||
本身。不要把 triage 的到期计数说成“已会建议”。
|
||
|
||
## 15. 使用量和连接状态管理
|
||
|
||
已实现(不新开端点,本批只做对照):
|
||
|
||
- 账户使用量:GET /users/me/quota、GET /tasks/{id}/cost
|
||
- 限制窗口剩余:quota 的美元配额与无价 token cap
|
||
- 连接的主机:GET /workers(心跳与主机名)
|
||
- 远程主机是否可用:worktree_host + /workers 心跳龄
|
||
(_workers_heartbeat)+ /health(db_ok、worker_ok)
|
||
- App 更新状态:/health 的 commit 字段(部署提交)
|
||
- 已安装插件和连接状态:第 12 项的 skills/mcp-servers
|
||
- 项目和线程的运行环境:第 6 项的 bindings
|
||
|
||
这些用于任务调度与故障判断,不直接跑任务。
|
||
|
||
## 本批新增端点一览
|
||
|
||
- GET /tasks/{id}/bindings
|
||
- POST /tasks/{id}/refs、GET /tasks/{id}/refs、
|
||
DELETE /tasks/{id}/refs/{ref_id}
|
||
- POST /tasks/{id}/worktree/archive、
|
||
GET /tasks/{id}/worktree/snapshots、
|
||
POST /tasks/{id}/worktree/restore
|
||
- GET/POST/DELETE /projects/{id}/automations/{aid}/bind
|
||
- POST /projects/{id}/automations/{aid}/heartbeat
|
||
- GET /projects/{id}/automations/{aid} 响应加
|
||
heartbeat_binding 字段
|
||
- GET /tasks/{id}/pr/checks 响应加 head_sha 字段
|
||
- 移交 completed 上报后任务 worktree_host 跟随切换
|