新增 run_tests.py:三套件统一入口,只加仓库根(deploy 套件 再加 deploy/ 目录在根之前),各套件走独立子进程;verify 作 业改走运行器,coverage 作业因子进程测不到覆盖率保持原 discover 命令。tests/ 13 个文件的 sys.path 前置 import 全部 改回正常 import(含 test_host_trace 的 try/except 回落); deploy 的 deploy 目录插入与 verify-multiuser 的 spec 加载按 陷阱 2 如实保留(仅删 verify-multiuser 冗余的根插入)。 .coveragerc omit 加 */run_tests.py,使新运行器文件不计入 生产覆盖率。门槛未动(仍 75%),未补新测试。
81 lines
2.9 KiB
Python
81 lines
2.9 KiB
Python
"""旧任务接续 goal 模式:host.py goal-resume --goal-text。
|
|
|
|
已终局的旧任务没有 goal 记录是正常情况,--goal-text 模式跳过
|
|
状态与记录守卫,在旧线程上从第 1 轮开新目标循环(新语义:
|
|
无验收、不传轮次时不限轮次,模型宣告完成才结束)。
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from unittest import mock
|
|
import host
|
|
|
|
|
|
class FakeServer(object):
|
|
def __init__(self, text):
|
|
self.text = text
|
|
self.resumed = []
|
|
|
|
def initialize(self):
|
|
pass
|
|
|
|
def close(self):
|
|
pass
|
|
|
|
def resume_thread(self, thread_id):
|
|
self.resumed.append(thread_id)
|
|
|
|
def run_turn(self, thread_id, prompt, model=None, effort=None,
|
|
sandbox=None, timeout=None):
|
|
return {"status": "completed", "text": self.text,
|
|
"turn_id": "u1"}
|
|
|
|
|
|
class GoalResumeTextTest(unittest.TestCase):
|
|
def _run_main(self, task, goal_text):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
state_path = os.path.join(tmp, "host-state.json")
|
|
cfg_path = os.path.join(tmp, "host-config.json")
|
|
with open(state_path, "w", encoding="utf-8") as f:
|
|
json.dump({"tasks": {"g": task}, "automations": []}, f)
|
|
with open(cfg_path, "w", encoding="utf-8") as f:
|
|
json.dump({}, f)
|
|
fake = FakeServer("done\n目标已达成")
|
|
argv = ["host.py", "--state", state_path,
|
|
"--config", cfg_path,
|
|
"goal-resume", "--task", "g"]
|
|
if goal_text is not None:
|
|
argv += ["--goal-text", goal_text]
|
|
with mock.patch.object(sys, "argv", argv):
|
|
with mock.patch.object(host, "Server",
|
|
lambda **kw: fake):
|
|
host.main()
|
|
with open(state_path, encoding="utf-8") as f:
|
|
saved = json.load(f)["tasks"]["g"]
|
|
return saved, fake
|
|
|
|
def test_goal_text_init_on_completed_task(self):
|
|
task = {"name": "g", "thread_id": "x", "cwd": "/tmp",
|
|
"sandbox": None, "max_retries": 0, "retry_count": 0,
|
|
"turns": [], "status": "completed"}
|
|
saved, fake = self._run_main(task, "new goal")
|
|
self.assertEqual(saved["status"], "goal-met")
|
|
self.assertEqual(saved["goal"], "new goal")
|
|
self.assertEqual(saved["goal_rounds_done"], 1)
|
|
self.assertEqual(fake.resumed, ["x"])
|
|
|
|
def test_goal_text_refuses_task_without_thread(self):
|
|
task = {"name": "g", "cwd": "/tmp",
|
|
"sandbox": None, "max_retries": 0, "retry_count": 0,
|
|
"turns": [], "status": "completed"}
|
|
saved, fake = self._run_main(task, "new goal")
|
|
self.assertEqual(saved["status"], "completed")
|
|
self.assertEqual(fake.resumed, [])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|