fix: 工具执行 IPC 卡死问题 — 多层超时保护

问题:确认工具操作后 Agent Loop 卡死在'正在思考中',工具未执行。

修复:
- tool-registry.ts: executeTool() 新增 25 秒 IPC 硬超时
- agent-engine.ts: executeTool 内部 .catch 捕获异常,防止 reject 逃逸
- ipc.ts: tool:execute handler 外层 try-catch 确保始终返回响应
- 全链路添加 console.log 便于排查
This commit is contained in:
Metona Dev
2026-04-06 20:41:56 +08:00
parent 509e402844
commit a9c56582d0
3 changed files with 34 additions and 12 deletions
+13 -7
View File
@@ -82,16 +82,22 @@ export function setupIPC(): void {
// ── Tool Calling IPC ──
ipcMain.handle('tool:execute', async (_, toolName: string, args: Record<string, unknown>) => {
try {
console.log('[IPC] tool:execute', toolName, JSON.stringify(args || {}).slice(0, 200));
switch (toolName) {
case 'read_file': return handleReadFile(args as { path: string; encoding?: string; start_line?: number; end_line?: number });
case 'write_file': return handleWriteFile(args as { path: string; content: string; encoding?: string });
case 'list_directory': return handleListDir(args as { path: string; recursive?: boolean; max_depth?: number; include_hidden?: boolean; filter_extension?: string });
case 'search_files': return handleSearchFiles(args as { path: string; query: string; search_type?: string; case_sensitive?: boolean; max_results?: number; file_extensions?: string[] });
case 'create_directory': return handleCreateDir(args as { path: string });
case 'delete_file': return handleDeleteFile(args as { path: string; recursive?: boolean });
case 'run_command': return handleRunCommand(args as { command: string; cwd?: string; timeout?: number });
case 'read_file': return await handleReadFile(args as { path: string; encoding?: string; start_line?: number; end_line?: number });
case 'write_file': return await handleWriteFile(args as { path: string; content: string; encoding?: string });
case 'list_directory': return await handleListDir(args as { path: string; recursive?: boolean; max_depth?: number; include_hidden?: boolean; filter_extension?: string });
case 'search_files': return await handleSearchFiles(args as { path: string; query: string; search_type?: string; case_sensitive?: boolean; max_results?: number; file_extensions?: string[] });
case 'create_directory': return await handleCreateDir(args as { path: string });
case 'delete_file': return await handleDeleteFile(args as { path: string; recursive?: boolean });
case 'run_command': return await handleRunCommand(args as { command: string; cwd?: string; timeout?: number });
default: return { success: false, error: `未知工具: ${toolName}` };
}
} catch (err) {
console.error('[IPC] tool:execute 异常:', toolName, err);
return { success: false, error: (err as Error).message || '工具执行异常' };
}
});
ipcMain.handle('tool:getConfig', () => ({
+9 -2
View File
@@ -283,9 +283,16 @@ export async function runAgentLoop(
try {
// 工具执行超时保护
console.log('[AgentEngine] 执行工具:', call.function.name);
logInfo(`执行工具: ${call.function.name}`, JSON.stringify(call.function.arguments));
const result = await Promise.race([
executeTool(call.function.name, call.function.arguments),
new Promise<never>((_, reject) =>
executeTool(call.function.name, call.function.arguments).then(r => {
console.log('[AgentEngine] executeTool resolve:', call.function.name, r);
return r;
}).catch(err => {
console.error('[AgentEngine] executeTool reject:', call.function.name, err);
return { success: false, error: err?.message || String(err) } as ToolResult;
}),
new Promise<ToolResult>((_, reject) =>
setTimeout(() => reject(new Error('工具执行超时(30秒)')), TOOL_EXEC_TIMEOUT)
)
]);
+10 -1
View File
@@ -159,10 +159,19 @@ export async function executeTool(toolName: string, args: Record<string, unknown
}
try {
const result = await bridge.tool.execute(toolName, args);
console.log('[ToolRegistry] 开始执行:', toolName, args);
// IPC 调用 + 25 秒硬超时(比 agent-engine 的 30 秒先触发)
const result = await Promise.race([
bridge.tool.execute(toolName, args),
new Promise<ToolResult>((_, reject) =>
setTimeout(() => reject(new Error(`工具 ${toolName} IPC 超时(25秒)`)), 25000)
)
]);
console.log('[ToolRegistry] 执行完成:', toolName, result);
return result;
} catch (err) {
logError(`工具异常: ${toolName}`, (err as Error).message);
console.error('[ToolRegistry] 执行异常:', toolName, err);
return { success: false, error: (err as Error).message };
}
}