refactor: 移除多余依赖,统一 MUI 为唯一 UI 库

- 移除 radix-ui、clsx、tailwind-merge、class-variance-authority、react-router-dom

- 前后端全面适配 MUI 组件,清理残留 Tailwind 工具类引用

- 优化 Agent Loop 引擎、IPC 处理器、Provider Adapter 等后端模块

- 新增 Agent 网络工具通用设计文档 v2
This commit is contained in:
thzxx
2026-07-05 19:15:48 +08:00
parent ba85328c4f
commit f4532a2bb2
50 changed files with 1474 additions and 2042 deletions
+93 -13
View File
@@ -20,6 +20,8 @@ import type { AuditService } from '../services/audit.service';
import type { SessionRecorder } from '../services/session-recorder.service';
import type { MemoryManager } from '../harness/memory/manager';
import type { MCPManager } from '../services/mcp-manager.service';
import type { PromptInjectionDefender } from '../harness/security/prompt-injection-defense';
import type { OutputValidator } from '../harness/verification/output-validator';
import type { MetonaMessage, MetonaStreamEvent } from '../harness/types';
import { MetonaErrorCode, MetonaStreamEventType } from '../harness/types';
import type { MetonaError } from '../harness/types';
@@ -35,12 +37,14 @@ export function registerAllIPCHandlers(
workspaceService: WorkspaceService,
contextBuilder: ContextBuilder,
agentLoop: AgentLoopEngine,
_toolRegistry: ToolRegistry,
toolRegistry: ToolRegistry,
auditService: AuditService,
sessionRecorder: SessionRecorder,
memoryManager: MemoryManager,
mcpManager: MCPManager,
reloadAdapter: () => void,
promptInjectionDefender: PromptInjectionDefender,
outputValidator: OutputValidator,
): void {
// ===== Agent 交互 =====
@@ -55,11 +59,12 @@ export function registerAllIPCHandlers(
auditService.logSessionStart(sessionId);
// 保存用户消息到数据库
// IPC boundary: frontend sends attachments not defined in the MetonaMessage type
sessionService.saveMessage({
sessionId,
role: 'user',
content: userMessage.content,
attachments: (userMessage as any).attachments,
attachments: (userMessage as MetonaMessage & { attachments?: unknown[] }).attachments,
});
// 加载历史消息
@@ -71,6 +76,8 @@ export function registerAllIPCHandlers(
role: m.role as MetonaMessage['role'],
content: m.content,
reasoningContent: m.reasoningContent,
toolCalls: m.toolCalls as MetonaMessage['toolCalls'],
toolResult: m.toolResult as MetonaMessage['toolResult'],
timestamp: m.timestamp,
}));
@@ -98,6 +105,40 @@ export function registerAllIPCHandlers(
agentLoop.on('stateChange', onStateChange);
try {
// 提示注入检测(安全模块)
const injectionResult = promptInjectionDefender.detect(userMessage.content);
if (injectionResult.riskScore >= 7) {
log.warn('[PromptInjectionDefender] Blocked message:', injectionResult.findings);
if (!mainWindow.isDestroyed()) {
const metonaError: MetonaError = {
code: MetonaErrorCode.UNKNOWN,
message: `Message blocked by prompt injection defense: ${injectionResult.recommendation}`,
retryable: false,
};
const errorEvent: MetonaStreamEvent = {
type: MetonaStreamEventType.ERROR,
requestId: '',
sessionId,
iteration: 0,
seq: 0,
timestamp: Date.now(),
error: metonaError,
};
mainWindow.webContents.send('agent:streamEvent', errorEvent);
}
// TRACE 层:停止录制
sessionRecorder.stopRecording({
totalIterations: 0,
totalTokens: 0,
durationMs: 0,
terminationReason: 'error',
});
return { success: false, error: 'Message blocked by prompt injection defense' };
}
if (injectionResult.riskScore >= 4) {
log.warn('[PromptInjectionDefender] Suspicious patterns detected:', injectionResult.findings);
}
// TRACE 层:记录上下文构建
sessionRecorder.recordContextBuilt({
tokenCount: history.reduce((sum, m) => sum + Math.ceil(m.content.length / 2), 0),
@@ -107,12 +148,47 @@ export function registerAllIPCHandlers(
// 启动 Agent Loop
const output = await agentLoop.runStream(userMessage, sessionId, history, systemPrompt);
// 保存 assistant 回复到数据库
sessionService.saveMessage({
sessionId,
role: 'assistant',
content: output.finalAnswer,
});
// 输出验证(不阻塞响应,仅记录警告)
try {
const validation = await outputValidator.validate(output.finalAnswer);
if (!validation.valid || validation.issues.length > 0) {
log.warn('[OutputValidator] Validation issues:', validation.issues);
}
log.debug(`[OutputValidator] Score: ${validation.score}, Valid: ${validation.valid}`);
} catch (err) {
log.error('[OutputValidator] Validation failed:', err);
}
// 保存每轮迭代的 assistant 消息到数据库(含思考内容和工具调用)
for (const step of output.iterations) {
if (!step.thought) continue;
// 将 MetonaToolCall + MetonaToolResult 转换为前端 ToolCallInfo 格式
const toolCallsWithResults = step.toolCalls?.map((tc) => {
const result = step.toolResults?.find((r) => r.toolCallId === tc.id);
return {
id: tc.id,
name: tc.name,
args: tc.args,
status: result?.success ? 'success' as const : 'error' as const,
result: result?.result,
durationMs: result?.durationMs,
error: result?.error,
};
});
// 只有当有内容、思考内容或工具调用时才保存
if (step.thought.content || step.thought.reasoningContent || toolCallsWithResults?.length) {
sessionService.saveMessage({
sessionId,
role: 'assistant',
content: step.thought.content,
reasoningContent: step.thought.reasoningContent || undefined,
toolCalls: toolCallsWithResults,
iteration: step.iteration,
});
}
}
// 更新 Token 统计
if (output.totalTokenUsage.totalTokens > 0) {
@@ -284,8 +360,8 @@ export function registerAllIPCHandlers(
try {
await mcpManager.removeServer(name);
return { success: true };
} catch {
return { success: false };
} catch (error) {
return { success: false, error: (error instanceof Error ? error.message : String(error)) };
}
});
@@ -293,8 +369,8 @@ export function registerAllIPCHandlers(
try {
await mcpManager.toggleServer(name, enabled);
return { success: true };
} catch {
return { success: false };
} catch (error) {
return { success: false, error: (error instanceof Error ? error.message : String(error)) };
}
});
@@ -363,7 +439,7 @@ export function registerAllIPCHandlers(
// ===== 工具管理 =====
ipcMain.handle('tools:list', async () => {
return _toolRegistry.listTools().map((t) => ({
return toolRegistry.listTools().map((t) => ({
name: t.name,
description: t.description,
category: t.category,
@@ -407,8 +483,10 @@ export function registerAllIPCHandlers(
ipcMain.handle('data:clearSessions', async () => {
try {
const db = sessionService.getDB();
db.exec('BEGIN');
db.exec('DELETE FROM messages');
db.exec('DELETE FROM sessions');
db.exec('COMMIT');
log.info('[DATA] All sessions cleared');
return { success: true };
} catch (error) {
@@ -433,6 +511,7 @@ export function registerAllIPCHandlers(
try {
// 审计日志是 INSERT-ONLY,需要先禁用触发器
const db = sessionService.getDB();
db.exec('BEGIN');
db.exec('DROP TRIGGER IF EXISTS audit_no_delete');
db.exec('DELETE FROM audit_logs');
db.exec(`
@@ -441,6 +520,7 @@ export function registerAllIPCHandlers(
SELECT RAISE(ABORT, 'Audit logs are INSERT-ONLY. Deletion is not allowed.');
END
`);
db.exec('COMMIT');
log.info('[DATA] Audit logs cleared');
return { success: true };
} catch (error) {