feat: goal 模式新语义——prompt 即目标,无验收命令,不限轮次,模型宣告完成 (#67)
console 打勾 goal 模式时不再有专用 goal 文本、验收命令、轮次 三个输入(已移除,换成说明行),只发 goal_mode=1;server 侧 goal_mode=1 时 goal 存 prompt、验收命令空、轮次存 0,带验收 命令或与计划模式同用时 400,旧的带验收命令任务照原样可用。 host.py goal 循环:verify 为空时不跑验测,轮次提示里写明 标记约定;模型在完整跑完的回合末尾单独一行输出“目标已 达成”即达标(超时回合的部分文本含标记也不算);--max-rounds 0 为不限轮次,goal-resume 续跑按 0 处理(不用 or 兜底成 3)。 刹车只有取消与预算耗尽(后者记 interrupted、可续跑)。 迁移与 worker:tasks 加 goal_mode 列(server 迁移、worker 列 补齐、PG schema 三处同步);worker 按 goal_mode 或 verify_command 判定 goal 路径,重试与后续消息排空对新语义 同样只跑一次/不排空;Local/Docker goal_task 的 --verify 可选、 --max-rounds 0 原样传。 Co-authored-by: host <host@test.local>
This commit is contained in:
1 parent
4179fb1a0a
commit
c86b450851
10 files changed
+519
-108
No files matched your search
@@ -889,6 +889,97 @@ class GoalLoopLongTaskTest(unittest.TestCase):
|
||||
self.assertEqual(task["status"], "goal-unmet")
|
||||
self.assertIn("verify timeout", task["goal_last_verify"])
|
||||
|
||||
def test_goal_llm_decided_met_on_marker_unlimited(self):
|
||||
# 新形态:verify=None、max_rounds=0(不限轮次);首轮提示
|
||||
# 含标记约定;第 2 轮模型输出标记行即达标。
|
||||
class FakeServer:
|
||||
def __init__(self):
|
||||
self.prompts = []
|
||||
|
||||
def run_turn(self, thread_id, prompt, model=None, effort=None,
|
||||
sandbox=None, timeout=None):
|
||||
self.prompts.append(prompt)
|
||||
if len(self.prompts) == 1:
|
||||
return {"status": "completed", "text": "working",
|
||||
"turn_id": "u1"}
|
||||
return {"status": "completed",
|
||||
"text": "done\n目标已达成",
|
||||
"turn_id": "u2"}
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
state_path = os.path.join(tmp, "host-state.json")
|
||||
state = {"tasks": {}, "automations": []}
|
||||
task = self._task(tmp)
|
||||
state["tasks"]["g"] = task
|
||||
srv = FakeServer()
|
||||
result = host.run_goal_loop(srv, state, state_path,
|
||||
task, "make it", None, 0, "m",
|
||||
"low", None, cfg={}, timeout=600)
|
||||
self.assertTrue(result["ok"])
|
||||
self.assertEqual(task["status"], "goal-met")
|
||||
self.assertEqual(task["goal_rounds_done"], 2)
|
||||
self.assertEqual(task["goal_max_rounds"], 0)
|
||||
self.assertIn("目标已达成", srv.prompts[0])
|
||||
self.assertIn("目标已达成", srv.prompts[1])
|
||||
|
||||
def test_goal_llm_decided_marker_ignored_on_timeout_turn(self):
|
||||
# 超时回合的部分文本即使含标记行也不算达标,必须继续跑。
|
||||
class FakeServer:
|
||||
def __init__(self):
|
||||
self.calls = 0
|
||||
|
||||
def run_turn(self, thread_id, prompt, model=None, effort=None,
|
||||
sandbox=None, timeout=None):
|
||||
self.calls += 1
|
||||
if self.calls == 1:
|
||||
return {"status": "timeout",
|
||||
"text": "partial\n目标已达成",
|
||||
"turn_id": "u1"}
|
||||
return {"status": "completed",
|
||||
"text": "done\n目标已达成",
|
||||
"turn_id": "u2"}
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
state_path = os.path.join(tmp, "host-state.json")
|
||||
state = {"tasks": {}, "automations": []}
|
||||
task = self._task(tmp)
|
||||
state["tasks"]["g"] = task
|
||||
result = host.run_goal_loop(FakeServer(), state, state_path,
|
||||
task, "make it", None, 0, "m",
|
||||
"low", None, cfg={}, timeout=600)
|
||||
self.assertTrue(result["ok"])
|
||||
self.assertEqual(task["status"], "goal-met")
|
||||
self.assertEqual(task["goal_rounds_done"], 2)
|
||||
|
||||
def test_goal_llm_decided_unlimited_past_three_rounds(self):
|
||||
# 0 = 不限轮次:第 4 轮才宣告也照常结束,不会被旧的
|
||||
# 默认 3 轮上限截断。
|
||||
class FakeServer:
|
||||
def __init__(self):
|
||||
self.calls = 0
|
||||
|
||||
def run_turn(self, thread_id, prompt, model=None, effort=None,
|
||||
sandbox=None, timeout=None):
|
||||
self.calls += 1
|
||||
if self.calls < 4:
|
||||
return {"status": "completed", "text": "working",
|
||||
"turn_id": "u%d" % self.calls}
|
||||
return {"status": "completed",
|
||||
"text": "done\n目标已达成",
|
||||
"turn_id": "u4"}
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
state_path = os.path.join(tmp, "host-state.json")
|
||||
state = {"tasks": {}, "automations": []}
|
||||
task = self._task(tmp)
|
||||
state["tasks"]["g"] = task
|
||||
result = host.run_goal_loop(FakeServer(), state, state_path,
|
||||
task, "make it", None, 0, "m",
|
||||
"low", None, cfg={}, timeout=600)
|
||||
self.assertTrue(result["ok"])
|
||||
self.assertEqual(task["status"], "goal-met")
|
||||
self.assertEqual(task["goal_rounds_done"], 4)
|
||||
|
||||
|
||||
|
||||
class ProgressInterruptTest(unittest.TestCase):
|
||||
|
||||
Reference in new issue
Block a user