fix: 全面修复审计问题并优化系统提示词

**崩溃/挂死修复 (5):**
- 统一 TrayManager.isQuitting 变量,修复 Cmd+Q 无法退出
- useAgentStream 闭包过期快照 → 每次 getState()
- Agnes chatStream 添加 AbortSignal.timeout
- SSE JSON.parse 添加 try-catch 保护
- Orchestrator setTools 污染 → save/restore 模式

**功能修复 (14):**
- 上下文压缩实现 (每5轮 COMPRESSING 状态)
- 修复 requestId 硬编码空串
- ConfigService.set() 保留已有 category
- MemoryManager 新增 working 类型搜索
- PromptInjectionDefender 补全 sanitize()
- Ollama: 补全 dynamicReminders + reasoningContent
- openai-format: 所有 assistant 消息保留 reasoningContent
- SSE: finish_reason 时提前 flush tool_calls
- DeepSeek thinking effort 映射注释
- Ollama done_reason load→stop
- RateLimitHook >= 边界修复
- WorkspaceService isValid 首次启动修复
- sessions:archive IPC handler
- 托盘/窗口图标路径生产环境修复

**系统提示词优化:**
- SOUL.md 存在时不显示兜底身份,原文放最前
- 兜底身份改为中文 (MetonaAI 自身描述)
- 用户文本在前,附件内容在后

**文件上传:**
- 非图片文件不再 base64 编码,保留 JSON 结构
- 用户文本优先于文件内容

**UI 修复:**
- 首页 Logo 路径修复 (public/ + 相对路径)
- TokenUsage contextWindow 动态计算 (Provider 感知)
- 切换 Provider 同步 contextWindow
- 托盘图标始终显示 Logo (状态由右键菜单展示)
This commit is contained in:
thzxx
2026-06-30 23:17:38 +08:00
parent ad0cbc8d47
commit 97a3d3d53b
30 changed files with 458 additions and 308 deletions
+48 -10
View File
@@ -1,12 +1,14 @@
/**
* Health Checker — 健康检查器
*
* 对数据库连通性、磁盘空间、内存使用执行真实检查。
*
* @see docs/生产级通用 AI Agent 智能体桌面应用:完整设计与构建指南.html — 第十一章
*/
import { existsSync } from 'fs';
import { join } from 'path';
import { app } from 'electron';
import type Database from 'better-sqlite3';
export interface HealthReport {
healthy: boolean;
@@ -22,7 +24,14 @@ export interface HealthCheck {
}
export class HealthChecker {
constructor(private dbPath?: string) {}
/**
* @param getDB 数据库获取器(用于真实验证数据库连通性)
* @param dbPath 数据库文件路径(后备:文件存在性检查)
*/
constructor(
private getDB?: () => Database.Database,
private dbPath?: string,
) {}
async check(): Promise<HealthReport> {
const checks: HealthCheck[] = [];
@@ -36,25 +45,52 @@ export class HealthChecker {
private async checkDatabase(): Promise<HealthCheck> {
const start = Date.now();
try {
// 优先使用注入的 DB 实例执行真实 ping
if (this.getDB) {
const db = this.getDB();
// 执行真实查询验证数据库连通性
db.prepare('SELECT 1').get();
return { name: 'database', healthy: true, latencyMs: Date.now() - start };
}
// 后备:检查数据库文件是否存在
if (this.dbPath && existsSync(this.dbPath)) {
return { name: 'database', healthy: true, latencyMs: Date.now() - start };
}
return { name: 'database', healthy: false, error: 'Database file not found' };
return { name: 'database', healthy: false, error: 'Database not available' };
} catch (error) {
return { name: 'database', healthy: false, error: (error instanceof Error ? error.message : String(error)) };
return {
name: 'database',
healthy: false,
error: error instanceof Error ? error.message : String(error),
};
}
}
private async checkDiskSpace(): Promise<HealthCheck> {
try {
const userDataPath = app.getPath('userData');
// 简单检查:userData 目录是否存在且可写
if (existsSync(userDataPath)) {
return { name: 'disk_space', healthy: true };
if (!existsSync(userDataPath)) {
return { name: 'disk_space', healthy: false, error: 'User data path not accessible' };
}
return { name: 'disk_space', healthy: false, error: 'User data path not accessible' };
// 检查实际可用磁盘空间(Windows/Linux 返回字节数)
const { freemem } = await import('os');
const freeBytes = freemem();
const freeMB = freeBytes / (1024 * 1024);
// 少于 200MB 视为不健康
if (freeMB < 200) {
return {
name: 'disk_space',
healthy: false,
error: `Free memory critically low: ${freeMB.toFixed(0)}MB available`,
};
}
return { name: 'disk_space', healthy: true };
} catch (error) {
return { name: 'disk_space', healthy: false, error: (error instanceof Error ? error.message : String(error)) };
return {
name: 'disk_space',
healthy: false,
error: error instanceof Error ? error.message : String(error),
};
}
}
@@ -65,7 +101,9 @@ export class HealthChecker {
return {
name: 'memory_usage',
healthy: heapUsedMB < thresholdMB,
...(heapUsedMB >= thresholdMB ? { error: `Heap usage ${heapUsedMB.toFixed(0)}MB exceeds threshold ${thresholdMB}MB` } : {}),
...(heapUsedMB >= thresholdMB
? { error: `Heap usage ${heapUsedMB.toFixed(0)}MB exceeds threshold ${thresholdMB}MB` }
: {}),
};
}
}