/** * Post-Tool Hooks — 工具执行后钩子 * * 用途:结果验证、审计日志写入、记忆触发、错误恢复建议。 * * @see docs/生产级通用 AI Agent 智能体桌面应用:完整设计与构建指南.html — 第五章 */ import type { MetonaToolCall, MetonaToolResult } from '../types'; import type { AuditService } from '../../services/audit.service'; import type { MemoryManager } from '../memory/manager'; import log from 'electron-log'; export interface PostToolHook { afterExecute(toolCall: MetonaToolCall, result: MetonaToolResult, sessionId: string): Promise; } /** 审计日志钩子 */ export class AuditLogHook implements PostToolHook { constructor(private auditService: AuditService) {} async afterExecute(toolCall: MetonaToolCall, result: MetonaToolResult, sessionId: string): Promise { this.auditService.logToolCall({ sessionId, iteration: toolCall.iteration, toolName: toolCall.name, args: toolCall.args, outcome: result.success ? 'success' : 'error', result: result.result, error: result.error, durationMs: result.durationMs, }); } } /** 记忆触发钩子 */ export class MemoryTriggerHook implements PostToolHook { /** 仅对搜索类工具触发记忆,避免每次 read_file 都产生低价值记忆条目 */ private memorableTools = ['web_search', 'memory_search']; /** 单次工具结果存储上限(字符),防止过大内容淹没记忆系统 */ private readonly MAX_MEMORY_CONTENT = 500; constructor(private memoryManager: MemoryManager) {} async afterExecute(toolCall: MetonaToolCall, result: MetonaToolResult, sessionId: string): Promise { if (this.memorableTools.includes(toolCall.name) && result.success) { const content = typeof result.result === 'string' ? result.result : JSON.stringify(result.result); try { this.memoryManager.store({ type: 'episodic', content: `Tool ${toolCall.name} returned: ${content.slice(0, this.MAX_MEMORY_CONTENT)}`, source: 'tool_result', sessionId, importance: 0.6, }); } catch (error) { // 记忆存储失败不应影响工具执行结果 log.error('[MemoryTriggerHook] Failed to store episodic memory:', error); } } } }