feat: enhance LocalAgent configuration and UI components

- Updated .env.example to provide clearer configuration instructions and API key setup.
- Removed debug_env.py as it was no longer needed.
- Refactored main.py to streamline application initialization and workspace setup.
- Introduced a new HistoryManager for managing task execution history.
- Enhanced UI components in chat_view.py and task_guide_view.py to improve user interaction and code preview functionality.
- Added loading indicators and improved task history display in the UI.
- Implemented unit tests for history management and intent classification.
This commit is contained in:
Mimikko-zeus
2026-01-07 10:29:13 +08:00
parent 1ba5f0f7d6
commit 0a92355bfb
18 changed files with 2144 additions and 557 deletions

189
history/manager.py Normal file
View File

@@ -0,0 +1,189 @@
"""
任务历史记录管理器
保存和加载任务执行历史
"""
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