"""子任务默认模型/强度(child_model / child_effort)单测。 不跑真实模型、不联网:解析是纯函数;服务端用本地临时端口 + 临时 SQLite(与 test_server_endpoints 同款骨架);worker 派生用临时 SQLite + _deliver_marker_tools(与 test_marker_tools 同款骨架,不走 run_one 全量流程)。 """ import http.client import json import os import sqlite3 import sys import tempfile import threading import time import unittest from pathlib import Path try: from cloud.auth import AuthStore from cloud.marker_tools import parse_spawn_defaults from cloud.server import create_server, init_db from cloud.worker import Worker except ImportError: sys.path.insert(0, str(Path(__file__).resolve().parents[2])) from cloud.auth import AuthStore from cloud.marker_tools import parse_spawn_defaults from cloud.server import create_server, init_db from cloud.worker import Worker FAKE_ENV = {"XCM_API_KEY": "test-placeholder"} class ParseSpawnDefaultsTestCase(unittest.TestCase): def test_user_example(self): self.assertEqual( parse_spawn_defaults("子代理用 gpt-6-luna max"), {"model": "gpt-6-luna", "effort": "max"}) def test_labelled_forms(self): self.assertEqual( parse_spawn_defaults("子任务模型:gpt-6-luna,强度:max"), {"model": "gpt-6-luna", "effort": "max"}) self.assertEqual( parse_spawn_defaults("子任务用 gpt-6.1-sol,effort high"), {"model": "gpt-6.1-sol", "effort": "high"}) def test_english_and_reversed(self): self.assertEqual( parse_spawn_defaults("subtasks use gpt-6-luna with effort max"), {"model": "gpt-6-luna", "effort": "max"}) self.assertEqual( parse_spawn_defaults("用 gpt-6-luna max 跑子任务"), {"model": "gpt-6-luna", "effort": "max"}) def test_no_false_positives(self): self.assertEqual( parse_spawn_defaults("子任务要写报告,不要用默认模型"), {}) self.assertEqual( parse_spawn_defaults("模型选择很重要,子任务用默认配置"), {}) # 裸说主线用 X 是本任务自己的模型,不算派生默认。 self.assertEqual(parse_spawn_defaults("主线用 gpt-6-luna max"), {}) # 跨子句的强度词不算。 self.assertEqual( parse_spawn_defaults("子任务用 gpt-6-luna。下一句强度是 high。"), {"model": "gpt-6-luna"}) class ServerChildModelTestCase(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.db_path = os.path.join(self.tmp.name, "control.db") self.auth = AuthStore(self.db_path) self.owner_id, self.owner_key = self.auth.create_user("owner") self.server = create_server(self.db_path, "127.0.0.1", 0) self.port = self.server.server_address[1] self.thread = threading.Thread( target=self.server.serve_forever, daemon=True) self.thread.start() status, self.project = self._req( "POST", "/projects", {"name": "demo"}, self.owner_key) self.assertEqual(status, 201) def tearDown(self): self.server.shutdown() self.server.server_close() self.thread.join(timeout=5) try: self.auth.conn.close() except Exception: pass self.tmp.cleanup() def _req(self, method, path, body=None, key=None): conn = http.client.HTTPConnection("127.0.0.1", self.port, timeout=10) hdrs = {} payload = None if body is not None: payload = json.dumps(body).encode("utf-8") hdrs["Content-Type"] = "application/json" if key is not None: hdrs["X-API-Key"] = key try: conn.request(method, path, body=payload, headers=hdrs) resp = conn.getresponse() data = resp.read() finally: conn.close() try: parsed = json.loads(data.decode("utf-8")) if data else None except ValueError: parsed = None return resp.status, parsed def _create(self, prompt, **extra): body = {"project_id": self.project["id"], "prompt": prompt} body.update(extra) status, task = self._req("POST", "/tasks", body, self.owner_key) self.assertEqual(status, 201, task) return task def _set_terminal(self, task_id): conn = sqlite3.connect(self.db_path) try: conn.execute( "UPDATE tasks SET status = 'completed' WHERE id = ?", (task_id,)) conn.commit() finally: conn.close() def test_create_explicit_child_fields(self): task = self._create( "做事", model="gpt-5.6-terra", effort="low", child_model="gpt-6-luna", child_effort="max") self.assertEqual(task["model"], "gpt-5.6-terra") self.assertEqual(task["child_model"], "gpt-6-luna") self.assertEqual(task["child_effort"], "max") def test_create_prompt_directive_fills_child_fields(self): task = self._create("子代理用 gpt-6-luna max,做三件事") self.assertEqual(task["child_model"], "gpt-6-luna") self.assertEqual(task["child_effort"], "max") # prompt 指令只填派生默认,不改本任务自己的模型。 self.assertIsNone(task["model"]) def test_create_explicit_wins_over_prompt(self): task = self._create( "子代理用 gpt-6-luna max", child_model="gpt-6-sol", child_effort="high") self.assertEqual(task["child_model"], "gpt-6-sol") self.assertEqual(task["child_effort"], "high") def test_create_invalid_child_effort_400(self): status, body = self._req("POST", "/tasks", { "project_id": self.project["id"], "prompt": "做事", "child_effort": "huge"}, self.owner_key) self.assertEqual(status, 400) def test_fork_copies_child_fields(self): parent = self._create( "做事", model="gpt-5.6-terra", child_model="gpt-6-luna", child_effort="max") self._set_terminal(parent["id"]) status, forked = self._req( "POST", "/tasks/%s/fork" % parent["id"], {"message": "继续"}, self.owner_key) self.assertEqual(status, 201, forked) self.assertEqual(forked["model"], "gpt-5.6-terra") self.assertEqual(forked["child_model"], "gpt-6-luna") self.assertEqual(forked["child_effort"], "max") def test_continue_updates_child_fields(self): task = self._create("做事") self._set_terminal(task["id"]) status, continued = self._req( "POST", "/tasks/%s/continue" % task["id"], {"message": "再跑一轮", "child_model": "gpt-6-luna", "child_effort": "max"}, self.owner_key) self.assertEqual(status, 200, continued) self.assertEqual(continued["child_model"], "gpt-6-luna") self.assertEqual(continued["child_effort"], "max") class WorkerChildModelTestCase(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.db_path = os.path.join(self.tmp.name, "control.db") init_db(self.db_path) self.auth = AuthStore(self.db_path) self.user_id, _key = self.auth.create_user("tester") self._insert("PM", status="running", model="gpt-5.6-terra", effort="low", child_model="gpt-6-luna", child_effort="max") def tearDown(self): try: self.auth.conn.close() except Exception: pass self.tmp.cleanup() def _insert(self, task_id, status="queued", **cols): now = time.time() conn = sqlite3.connect(self.db_path) try: conn.execute( "INSERT INTO tasks(id, project_id, prompt, status," " idempotency_key, depends_on, priority, created_by," " created_at, updated_at, last_heartbeat)" " VALUES(?, 'p1', 'do work', ?, NULL, '[]', 0, 'tester'," " ?, ?, NULL)", (task_id, status, now, now)) for key, value in cols.items(): conn.execute( "UPDATE tasks SET %s = ? WHERE id = ?" % key, (value, task_id)) conn.commit() finally: conn.close() def _child_row(self): conn = sqlite3.connect(self.db_path) try: return conn.execute( "SELECT model, effort, child_model, child_effort" " FROM tasks WHERE parent_task_id = 'PM'").fetchone() finally: conn.close() def _deliver(self, creates): worker = Worker(self.db_path, "/fake/host.py", env=FAKE_ENV) worker._deliver_marker_tools(worker.get_task("PM"), { "status": "completed", "task_creates": creates, "task_polls": [], "wait_threads": [], "task_cancels": [], "task_retries": []}) def test_marker_inherits_child_defaults_when_block_blank(self): self._deliver([{"name": "E1", "prompt": "do e1", "model": None, "effort": None, "executor": None}]) row = self._child_row() self.assertIsNotNone(row) self.assertEqual(row[0], "gpt-6-luna") self.assertEqual(row[1], "max") # 派生默认本身也传给子任务,隔代派生不丢。 self.assertEqual(row[2], "gpt-6-luna") self.assertEqual(row[3], "max") def test_marker_explicit_block_wins(self): self._deliver([{"name": "E1", "prompt": "do e1", "model": "gpt-6-sol", "effort": "high", "executor": None}]) row = self._child_row() self.assertEqual(row[0], "gpt-6-sol") self.assertEqual(row[1], "high") def test_marker_falls_back_to_parent_model_without_child_defaults(self): conn = sqlite3.connect(self.db_path) try: conn.execute( "UPDATE tasks SET child_model = NULL," " child_effort = NULL WHERE id = 'PM'") conn.commit() finally: conn.close() self._deliver([{"name": "E1", "prompt": "do e1", "model": None, "effort": None, "executor": None}]) row = self._child_row() self.assertEqual(row[0], "gpt-5.6-terra") self.assertEqual(row[1], "low") def test_coordinator_inherits_child_defaults(self): worker = Worker(self.db_path, "/fake/host.py", env=FAKE_ENV) parent = worker.get_task("PM") children = worker._coord_sync_children(parent, [ {"name": "后端", "prompt": "做后端", "model": None, "effort": None, "executor": None}]) self.assertEqual(len(children), 1) conn = sqlite3.connect(self.db_path) try: row = conn.execute( "SELECT model, effort FROM tasks WHERE id = ?", (children[0]["id"],)).fetchone() finally: conn.close() self.assertEqual(row[0], "gpt-6-luna") self.assertEqual(row[1], "max") if __name__ == "__main__": unittest.main()