""" 任务历史记录管理器 保存和加载任务执行历史 """ import json from datetime import datetime from pathlib import Path from typing import Optional, List from dataclasses import dataclass, asdict @dataclass class TaskRecord: """任务记录""" task_id: str timestamp: str user_input: str intent_label: str intent_confidence: float execution_plan: str code: str success: bool duration_ms: int stdout: str stderr: str log_path: str class HistoryManager: """ 历史记录管理器 将任务历史保存为 JSON 文件 """ MAX_HISTORY_SIZE = 100 # 最多保存 100 条记录 def __init__(self, workspace_path: Optional[Path] = None): if workspace_path: self.workspace = workspace_path else: self.workspace = Path(__file__).parent.parent / "workspace" self.history_file = self.workspace / "history.json" self._history: List[TaskRecord] = [] self._load() def _load(self): """从文件加载历史记录""" if self.history_file.exists(): try: with open(self.history_file, 'r', encoding='utf-8') as f: data = json.load(f) self._history = [TaskRecord(**record) for record in data] except (json.JSONDecodeError, TypeError, KeyError) as e: print(f"[警告] 加载历史记录失败: {e}") self._history = [] else: self._history = [] def _save(self): """保存历史记录到文件""" try: # 确保目录存在 self.history_file.parent.mkdir(parents=True, exist_ok=True) with open(self.history_file, 'w', encoding='utf-8') as f: data = [asdict(record) for record in self._history] json.dump(data, f, ensure_ascii=False, indent=2) except Exception as e: print(f"[警告] 保存历史记录失败: {e}") def add_record( self, task_id: str, user_input: str, intent_label: str, intent_confidence: float, execution_plan: str, code: str, success: bool, duration_ms: int, stdout: str = "", stderr: str = "", log_path: str = "" ) -> TaskRecord: """ 添加一条任务记录 Args: task_id: 任务 ID user_input: 用户输入 intent_label: 意图标签 intent_confidence: 意图置信度 execution_plan: 执行计划 code: 生成的代码 success: 是否执行成功 duration_ms: 执行耗时(毫秒) stdout: 标准输出 stderr: 标准错误 log_path: 日志文件路径 Returns: TaskRecord: 创建的记录 """ record = TaskRecord( task_id=task_id, timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), user_input=user_input, intent_label=intent_label, intent_confidence=intent_confidence, execution_plan=execution_plan, code=code, success=success, duration_ms=duration_ms, stdout=stdout, stderr=stderr, log_path=log_path ) # 添加到列表开头(最新的在前) self._history.insert(0, record) # 限制历史记录数量 if len(self._history) > self.MAX_HISTORY_SIZE: self._history = self._history[:self.MAX_HISTORY_SIZE] # 保存 self._save() return record def get_all(self) -> List[TaskRecord]: """获取所有历史记录""" return self._history.copy() def get_recent(self, count: int = 10) -> List[TaskRecord]: """获取最近的 N 条记录""" return self._history[:count] def get_by_id(self, task_id: str) -> Optional[TaskRecord]: """根据任务 ID 获取记录""" for record in self._history: if record.task_id == task_id: return record return None def clear(self): """清空历史记录""" self._history = [] self._save() def get_stats(self) -> dict: """获取统计信息""" if not self._history: return { 'total': 0, 'success': 0, 'failed': 0, 'success_rate': 0.0, 'avg_duration_ms': 0 } total = len(self._history) success = sum(1 for r in self._history if r.success) failed = total - success avg_duration = sum(r.duration_ms for r in self._history) / total return { 'total': total, 'success': success, 'failed': failed, 'success_rate': success / total if total > 0 else 0.0, 'avg_duration_ms': int(avg_duration) } # 全局单例 _manager: Optional[HistoryManager] = None def get_history_manager(workspace_path: Optional[Path] = None) -> HistoryManager: """获取历史记录管理器单例""" global _manager if _manager is None: _manager = HistoryManager(workspace_path) return _manager