diff --git a/src/daemon/dispatcher.py b/src/daemon/dispatcher.py index 5351dbc..5f2b47e 100644 --- a/src/daemon/dispatcher.py +++ b/src/daemon/dispatcher.py @@ -189,13 +189,16 @@ class Dispatcher: # on_checks_passed: 所有检查通过后才标 working,检查失败不标 on_checks_passed = None + _mail_marked_working = False if is_mail and db_path: _task_id = task.id _mail_db = db_path _disp = self def _mail_on_checks_passed(): + nonlocal _mail_marked_working if not _disp._mail_auto_working(_task_id, _mail_db): raise RuntimeError("mail_auto_working_failed") + _mail_marked_working = True on_checks_passed = _mail_on_checks_passed # 构建 spawn message @@ -242,9 +245,7 @@ class Dispatcher: "reason": decision["reason"], } except AgentBusyError: - # v2.7.2: agent 被 counter 占用或冷却中 - # v2.7.3: on_checks_passed 在 check 通过后才标 working, - # 所以 AgentBusyError 时 working 未被标记,无需回退 + # on_checks_passed 未执行(check 失败在它之前),working 未标,无需回退 self._record_routing(task, decision, "skipped", "Agent busy", _routing_db) return { "level": level.value, @@ -254,6 +255,9 @@ class Dispatcher: "reason": "Agent busy (concurrent limit or cooling down)", } except Exception as e: + # on_checks_passed 已执行但 subprocess 失败 → 回退 working → pending + if _mail_marked_working: + self._mail_revert_to_pending(task.id, db_path) self._record_routing(task, decision, "error", str(e), _routing_db) return { "level": level.value,