From 69ab812c8aa3618d7898cc8ff6ad45dcfca9c302 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Tue, 19 May 2026 23:08:06 +0800 Subject: [PATCH] auto-sync: 2026-05-19 23:08:06 --- src/daemon/ticker.py | 76 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/daemon/ticker.py b/src/daemon/ticker.py index 7d1697e..aad1097 100644 --- a/src/daemon/ticker.py +++ b/src/daemon/ticker.py @@ -625,6 +625,82 @@ class Ticker: except Exception: return False + # ------------------------------------------------------------------ + # 经验蒸馏 + # ------------------------------------------------------------------ + + def _distill_completed_tasks(self, db_path: Path, + project_id: str) -> List[str]: + """从已完成的任务中蒸馏经验""" + queries = Queries(db_path) + distilled_ids: List[str] = [] + + # 找 done/failed/cancelled 的任务 + for status in ("done", "failed", "cancelled"): + tasks = queries.tasks_by_status(status) + for task in tasks: + # 只蒸馏有产出的任务 + bb = Blackboard(db_path) + outputs = bb.get_outputs(task.id) + if not outputs: + continue + + # 获取 review 结果(如果有) + reviews = bb.get_reviews(task.id) + review_result = None + if reviews: + latest = reviews[-1] + review_result = latest if isinstance(latest, dict) else {"verdict": "unknown"} + + # 格式化产出 + output_dicts = [] + for out in outputs: + output_dicts.append({ + "content": out.get("content", "") if isinstance(out, dict) else "", + "path": out.get("content_path", "") if isinstance(out, dict) else "", + }) + + try: + experiences = self.experience_distiller.distill_from_task( + task_id=task.id, + task_title=task.title, + task_type=getattr(task, 'task_type', None), + outputs=output_dicts, + review_result=review_result, + agent_id=task.current_agent or task.assignee, + ) + if experiences: + distilled_ids.append(task.id) + logger.info("Distilled %d experiences from task %s", + len(experiences), task.id) + except Exception: + logger.exception("Distill failed for task %s", task.id) + + return distilled_ids + + # ------------------------------------------------------------------ + # InboxWatcher 即时 tick 回调 + # ------------------------------------------------------------------ + + async def _on_inbox_event(self, event: Dict[str, Any]) -> None: + """InboxWatcher 事件回调:处理事件 + 触发即时 tick""" + logger.info("Inbox event received: type=%s project=%s", + event.get("type"), event.get("project_id")) + + # 1. 通过 default_inbox_callback 处理事件(更新黑板) + try: + from src.daemon.inbox import default_inbox_callback + await default_inbox_callback( + event, + registry_root=self.registry.root, + initialized_dbs=self._initialized_dbs, + ) + except Exception: + logger.exception("Inbox callback error") + + # 2. 设置 event flag,触发即时 tick + self._inbox_event.set() + # ------------------------------------------------------------------ # 手动 tick(API 端点触发) # ------------------------------------------------------------------