From bfd6db86cfb235fb40bba635595874aff88235c6 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Wed, 3 Jun 2026 09:04:27 +0800 Subject: [PATCH] auto-sync: 2026-06-03 09:04:27 --- src/daemon/ticker.py | 75 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/src/daemon/ticker.py b/src/daemon/ticker.py index 4896e52..b239bd9 100644 --- a/src/daemon/ticker.py +++ b/src/daemon/ticker.py @@ -706,13 +706,74 @@ Parent Task ID: {parent_task.id} prompt = self._build_mention_prompt( agent_id, task, mention_lines, project_id) - # spawn - result = await self.spawner.spawn_full_agent( - agent_id=agent_id, - message=prompt, - task_id=tid, - use_main_session=True, # #02: 投递到 main session - ) + # #09: 检测 rebuttal 场景 — review 状态的任务 + rebuttal comment + is_rebuttal_review = False + if task and task.status == "review": + for item in items: + ct = item.get("comment_type", "") + if ct == "rebuttal": + is_rebuttal_review = True + break + + if is_rebuttal_review: + # rebuttal 重审:带 on_complete 回调处理新 verdict + _ticker = self + _pid = project_id + _t_id = tid + + async def _rebuttal_on_complete(aid: str, outcome: str): + try: + if outcome in ("completed", "session_revived"): + # 读新 verdict + rdb_path = _ticker._resolve_db_path(_pid) + rconn = get_connection(rdb_path) + try: + new_review = rconn.execute( + "SELECT verdict FROM reviews WHERE task_id=? ORDER BY created_at DESC LIMIT 1", + (_t_id,) + ).fetchone() + finally: + rconn.close() + + if new_review and new_review["verdict"] == "approved": + _ticker._transition_status( + get_connection(rdb_path), _t_id, "done", + agent="daemon", + detail={"reason": "rebuttal_approved"}) + logger.info("Rebuttal: task %s approved after rebuttal", _t_id) + else: + # 仍非 approved → @mention assignee + verdict_str = new_review["verdict"] if new_review else "未知" + rconn2 = get_connection(rdb_path) + try: + t_row = rconn2.execute("SELECT assignee FROM tasks WHERE id=?", (_t_id,)).fetchone() + finally: + rconn2.close() + if t_row and t_row["assignee"]: + from src.blackboard.blackboard import Blackboard + bb2 = Blackboard(rdb_path) + bb2.add_comment(_t_id, "daemon", + f"@{t_row['assignee']} 审查结论: {verdict_str},请查看详情并决定接受或反驳", + comment_type="review") + logger.info("Rebuttal: task %s still %s after rebuttal", _t_id, verdict_str) + except Exception: + logger.exception("Rebuttal on_complete failed for task %s", _t_id) + + result = await self.spawner.spawn_full_agent( + agent_id=agent_id, + message=prompt, + task_id=tid, + use_main_session=True, + on_complete=_rebuttal_on_complete, + ) + else: + # 普通 mention:不带回调 + result = await self.spawner.spawn_full_agent( + agent_id=agent_id, + message=prompt, + task_id=tid, + use_main_session=True, # #02: 投递到 main session + ) if result is not None: # 成功 → 标记所有该 agent 的 mentions 为 notified