diff --git a/tests/test_e2e_v31.py b/tests/test_e2e_v31.py index e010bcc..f05ec11 100644 --- a/tests/test_e2e_v31.py +++ b/tests/test_e2e_v31.py @@ -677,3 +677,119 @@ class TestE10dFullLifecycle: print(f" done→cancelled: ✅") print(f" ✅ E10d 完整生命周期测试通过") + + +# =================================================================== +# E15: Prompt v3.0 广播三级响应 E2E +# =================================================================== + +@pytest.mark.integration +@pytest.mark.skipif(not os.environ.get("RUN_INTEGRATION"), + reason="Set RUN_INTEGRATION=1 to run real agent tests") +class TestE15PromptV3Broadcast: + """E15: Prompt v3.0 广播认领三级响应 E2E + + 创建一个 assignee 不匹配任何已注册 Agent 的任务, + 验证广播后 Agent 写了 observation comment(而非静默 NO_REPLY)。 + """ + + @pytest.fixture(autouse=True) + def setup_env(self): + _check_environment() + self._projects = [] + yield + for pid in self._projects: + _cleanup_project(pid) + + def test_broadcast_observation_comment(self): + """广播任务 → Agent 写 observation comment + + Prompt v3.0 的 _build_claim_prompt 三级响应: + - 匹配 → claim + - 不匹配但能帮忙 → observation comment + - 不匹配且帮不上 → NO_REPLY(静默) + + 创建一个 assignee=simayi-challenger 但 task_type=coding 的任务, + 司马懿收到后应写 observation comment(挑战者视角),而不是执行。 + """ + pid = _create_project(self._projects, "E15", + agents=["simayi-challenger"]) + tid = _create_task( + pid, + title="E2E Prompt v3.0:观察型任务", + description=( + "这是一个编码任务,但 assignee 是司马懿。\n" + "按照 Prompt v3.0 三级响应:\n" + "- 如果你认为应该由其他人执行,请写 observation comment\n" + "- 不需要实际执行编码\n" + "- 标记 done 即可\n" + "这是E2E测试,验证广播三级响应。" + ), + assignee="simayi-challenger", + task_type="coding", + ) + + print(f"\n🚀 E15: 等待广播认领+Agent响应 (pid={pid}, tid={tid})") + result = _poll_task( + pid, tid, timeout=MAX_WAIT_AGENT, + terminal_states=("done", "failed", "cancelled", "blocked"), + ) + status = result.get("status") + print(f" 最终状态: {status}") + + assert status != "pending", "任务未被调度" + + # 检查是否有 comment(Agent 响应的证据) + db_path = _get_db_path(pid) + if db_path.exists(): + import sqlite3 as sq3 + conn = sq3.connect(str(db_path)) + try: + comments = conn.execute( + "SELECT author, comment_type, body FROM comments " + "WHERE task_id=? ORDER BY id DESC LIMIT 5", + (tid,), + ).fetchall() + print(f" Comments ({len(comments)}):") + for c in comments: + print(f" [{c[0]}] {c[1]}: {c[2][:80]}...") + # 应该有至少一个 comment(Agent 的响应) + assert len(comments) > 0, ( + f"Agent 未写任何 comment,Prompt v3.0 三级响应可能未生效" + ) + finally: + conn.close() + + print(f" ✅ Prompt v3.0 广播响应验证完成") + + def test_broadcast_claim_by_matching_agent(self): + """广播任务 → 匹配 Agent 执行 claim → done + + 对比测试:正确 assignee 的任务应被认领并执行。 + """ + pid = _create_project(self._projects, "E15b", + agents=["zhangfei-dev"]) + tid = _create_task( + pid, + title="E2E Prompt v3.0:认领型任务", + description=( + "请执行 echo claim-test 并标记done。\n" + "这是E2E测试,验证正确 assignee 的任务被认领执行。\n" + "不需要做其他事。" + ), + assignee="zhangfei-dev", + task_type="coding", + ) + + print(f"\n🚀 E15b: 等待正确Agent认领 (pid={pid}, tid={tid})") + result = _poll_task( + pid, tid, timeout=MAX_WAIT_AGENT, + terminal_states=("done", "failed", "cancelled", "blocked"), + ) + status = result.get("status") + print(f" 最终状态: {status}") + + assert status != "pending", "任务未被认领" + assert status != "blocked", "任务被错误拦截" + + print(f" ✅ 正确 assignee 认领执行验证通过")