feat: 旧任务继续会话——终端任务带新消息 + 全部选项同一会话续跑

server:POST /tasks/{id}/continue(终端非 merged 任务重排队,
resume_message 列存本轮消息,不传选项沿用原值,plan/goal 冲突
与新建一致,goal_mode=1 时转新 goal 语义;CAS 防并发改状态,
审计 task_continued);tasks.resume_message 三处迁移 + PG 建表。
worker:认领后本轮 prompt 换成续跑消息(只换内存副本),
goal 续跑走 goal-resume 而不是 goal,跑完清 resume_message
(进程被杀时不清,下次认领重跑同一条消息)。
host:goal-resume --goal-text(旧任务接续 goal 模式:跳过状态
与记录守卫,旧线程上从第 1 轮开新目标循环,新语义不限轮次;
无线程时拒绝)。
sandbox:Local/Docker goal_resume_task + popen goal-resume kind;
附带 popen goal 命令改成新语义(无验收不传 --verify,轮次 0
原样传,此前 goal 任务到本地 worker 会直接报错)。
console:详情页终端非 merged 任务出继续会话表单(消息 +
模型/强度/权限/计划/goal,模型下拉复用中转列表)。
测试:新增 test_task_continue.py 11 个 + test_host_continue.py 2 个。
This commit is contained in:
host committed 2026-10-27 04:40:11 +08:00
1 parent cf293914d9
commit 3a4997d346
9 files changed
+823 -20

No files matched your search

+27
View File
@@ -1992,6 +1992,10 @@ def main():
help="验测命令上限(秒);0 表示不限时,默认 600")
p = sub.add_parser("goal-resume")
p.add_argument("--task", required=True)
p.add_argument("--goal-text", default=None,
help="新目标文本:旧任务接续 goal 模式时用——跳过状态与"
"goal 记录守卫,在旧线程上从第 1 轮开新目标循环"
"(新语义:无验收、不传 --max-rounds 时不限轮次)")
p.add_argument("--max-rounds", type=int, default=None,
help="不传时沿用原任务的 goal_max_rounds;传了则覆盖总轮次")
p.add_argument("--verify-timeout", type=int, default=600,
@@ -2583,6 +2587,29 @@ def main():
verify_timeout=args.verify_timeout)
elif args.cmd == "goal-resume":
t = state["tasks"][args.task]
if args.goal_text:
# 旧任务接续 goal 模式(云端 /continue 带 goal_mode=1
# 时走这里):旧任务已终局、没有 goal 记录是正常情况,
# 不能按断点续跑的守卫拒绝。只要线程还在,就在旧线程
# 上从第 1 轮开新目标循环(新语义:无验收、不传轮次
# 时不限轮次,模型宣告完成才结束)。
if not t.get("thread_id"):
print(f"goal-resume 拒绝:{args.task} 没有会话线程,"
f"不能接续")
return
max_rounds = args.max_rounds \
if args.max_rounds is not None else 0
srv.resume_thread(t["thread_id"])
run_goal_loop(srv, state, args.state, t, args.goal_text,
None, max_rounds,
args.model, args.effort, args.sandbox, cfg=cfg,
timeout=args.turn_timeout,
verify_timeout=args.verify_timeout,
start_round=1,
last_verify="",
last_turn_status=None,
last_turn_text="")
return
if t.get("status") not in ("goal-running", "interrupted",
"running"):
print(f"goal-resume 拒绝:{args.task} 当前状态是 "