From 0489952cebcf14cf03c0ce30e0f3299549c67f86 Mon Sep 17 00:00:00 2001 From: thzxx Date: Wed, 10 Jun 2026 09:54:20 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=B6=85=E6=97=B6=E8=AE=BE=E7=BD=AE0?= =?UTF-8?q?=E5=80=BC(=E7=A6=81=E7=94=A8)=E6=97=A0=E6=B3=95=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 保存值改用-1表示默认, 0表示禁用, 正数表示自定义秒数 - 修复parseSec区分空字符串和0值 - loadTimeoutSettings/main.ts初始化同步更新判断逻辑 - 补全types.d.ts中setTimeouts类型声明 --- src/renderer/components/settings-modal.ts | 47 ++++++++++++----------- src/renderer/main.ts | 28 +++++++------- src/renderer/types.d.ts | 1 + 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/renderer/components/settings-modal.ts b/src/renderer/components/settings-modal.ts index 3460a7d..c62dced 100644 --- a/src/renderer/components/settings-modal.ts +++ b/src/renderer/components/settings-modal.ts @@ -73,30 +73,33 @@ export function initSettingsModal(): void { const db = state.get(KEYS.DB); const bridge = window.metonaDesktop; + // 辅助:解析输入值,空→-1(默认),数字→该值(含0=禁用) + const parseSec = (val: string): number => (val !== '' ? parseInt(val) : -1); + // HTTP 超时(秒→毫秒) - const httpVal = inputHttpTimeout.value.trim(); - const httpSec = httpVal ? parseInt(httpVal) : 0; - if (db) await db.saveSetting('httpTimeout', httpSec > 0 ? httpSec : 0); + const httpSec = parseSec(inputHttpTimeout.value.trim()); + const httpMs = httpSec >= 0 ? httpSec * 1000 : 30_000; + if (db) await db.saveSetting('httpTimeout', httpSec); if (bridge?.tool?.setTimeouts) { - await bridge.tool.setTimeouts({ http: httpSec > 0 ? httpSec * 1000 : 30_000 }); + await bridge.tool.setTimeouts({ http: httpMs }); } - logInfo('HTTP 超时', httpSec > 0 ? `${httpSec}s` : '默认(30s)'); + logInfo('HTTP 超时', httpSec >= 0 ? (httpSec === 0 ? '已禁用' : `${httpSec}s`) : '默认(30s)'); // 流式超时(秒→毫秒) - const streamVal = inputStreamTimeout.value.trim(); - const streamSec = streamVal ? parseInt(streamVal) : 0; - state.set('streamTimeout', streamSec > 0 ? streamSec * 1000 : 300_000); - if (db) await db.saveSetting('streamTimeout', streamSec > 0 ? streamSec : 0); - logInfo('流式超时', streamSec > 0 ? `${streamSec}s` : '默认(300s)'); + const streamSec = parseSec(inputStreamTimeout.value.trim()); + const streamMs = streamSec >= 0 ? streamSec * 1000 : 300_000; + state.set('streamTimeout', streamMs); + if (db) await db.saveSetting('streamTimeout', streamSec); + logInfo('流式超时', streamSec >= 0 ? (streamSec === 0 ? '已禁用' : `${streamSec}s`) : '默认(300s)'); // MCP 超时(秒→毫秒) - const mcpVal = inputMCPTimeout.value.trim(); - const mcpSec = mcpVal ? parseInt(mcpVal) : 0; - if (db) await db.saveSetting('mcpTimeout', mcpSec > 0 ? mcpSec : 0); + const mcpSec = parseSec(inputMCPTimeout.value.trim()); + const mcpMs = mcpSec >= 0 ? mcpSec * 1000 : 60_000; + if (db) await db.saveSetting('mcpTimeout', mcpSec); if (bridge?.tool?.setTimeouts) { - await bridge.tool.setTimeouts({ mcp: mcpSec > 0 ? mcpSec * 1000 : 60_000 }); + await bridge.tool.setTimeouts({ mcp: mcpMs }); } - logInfo('MCP 超时', mcpSec > 0 ? `${mcpSec}s` : '默认(60s)'); + logInfo('MCP 超时', mcpSec >= 0 ? (mcpSec === 0 ? '已禁用' : `${mcpSec}s`) : '默认(60s)'); }; const saveHttpTimeout = debounce(applyTimeouts, 500); @@ -309,22 +312,22 @@ export function closeSettingsModal(): void { settingsModalEl.style.display = 'none'; } -/** 加载已保存的超时设置到输入框 */ +/** 加载已保存的超时设置到输入框:-1=默认(显示空), 0=禁用, 正数=自定义 */ async function loadTimeoutSettings(): Promise { const db = state.get(KEYS.DB); if (!db) return; - const httpTimeout = await db.getSetting('httpTimeout', 0); - const streamTimeout = await db.getSetting('streamTimeout', 0); - const mcpTimeout = await db.getSetting('mcpTimeout', 0); + const httpTimeout = await db.getSetting('httpTimeout', -1); + const streamTimeout = await db.getSetting('streamTimeout', -1); + const mcpTimeout = await db.getSetting('mcpTimeout', -1); const inputHttp = document.querySelector('#inputHttpTimeout') as HTMLInputElement; const inputStream = document.querySelector('#inputStreamTimeout') as HTMLInputElement; const inputMCP = document.querySelector('#inputMCPTimeout') as HTMLInputElement; - if (inputHttp) inputHttp.value = httpTimeout > 0 ? String(httpTimeout) : ''; - if (inputStream) inputStream.value = streamTimeout > 0 ? String(streamTimeout) : ''; - if (inputMCP) inputMCP.value = mcpTimeout > 0 ? String(mcpTimeout) : ''; + if (inputHttp) inputHttp.value = httpTimeout >= 0 ? String(httpTimeout) : ''; + if (inputStream) inputStream.value = streamTimeout >= 0 ? String(streamTimeout) : ''; + if (inputMCP) inputMCP.value = mcpTimeout >= 0 ? String(mcpTimeout) : ''; } async function exportAllSessions(): Promise { diff --git a/src/renderer/main.ts b/src/renderer/main.ts index 101ccd2..4dccf7e 100644 --- a/src/renderer/main.ts +++ b/src/renderer/main.ts @@ -362,30 +362,28 @@ async function init(): Promise { state.set('maxTurns', maxTurns); (document.querySelector('#inputMaxTurns') as HTMLInputElement).value = String(maxTurns); - // ── v5.2 超时设置 ── - const httpTimeout = await db.getSetting('httpTimeout', 0); - const streamTimeout = await db.getSetting('streamTimeout', 0); - const mcpTimeout = await db.getSetting('mcpTimeout', 0); + // ── v5.2 超时设置:-1=默认, 0=禁用, 正数=自定义 ── + const httpTimeout = await db.getSetting('httpTimeout', -1); + const streamTimeout = await db.getSetting('streamTimeout', -1); + const mcpTimeout = await db.getSetting('mcpTimeout', -1); - // 应用流式超时到 state(agent-engine 会读取) - state.set('streamTimeout', streamTimeout > 0 ? streamTimeout * 1000 : 300_000); + // 应用流式超时到 state(agent-engine 读取,0=禁用) + state.set('streamTimeout', streamTimeout >= 0 ? streamTimeout * 1000 : 300_000); // 应用 HTTP 和 MCP 超时到主进程 const bridge = window.metonaDesktop; if (bridge?.tool?.setTimeouts) { await bridge.tool.setTimeouts({ - http: httpTimeout > 0 ? httpTimeout * 1000 : 30_000, - mcp: mcpTimeout > 0 ? mcpTimeout * 1000 : 60_000, + http: httpTimeout >= 0 ? httpTimeout * 1000 : 30_000, + mcp: mcpTimeout >= 0 ? mcpTimeout * 1000 : 60_000, }); } - // 恢复输入框显示值 - if (document.querySelector('#inputHttpTimeout')) { - (document.querySelector('#inputHttpTimeout') as HTMLInputElement).value = httpTimeout > 0 ? String(httpTimeout) : ''; - (document.querySelector('#inputStreamTimeout') as HTMLInputElement).value = streamTimeout > 0 ? String(streamTimeout) : ''; - (document.querySelector('#inputMCPTimeout') as HTMLInputElement).value = mcpTimeout > 0 ? String(mcpTimeout) : ''; - } - logInit(`超时设置: HTTP=${httpTimeout||30}s 流式=${streamTimeout||300}s MCP=${mcpTimeout||60}s`); + // 恢复输入框显示(-1显示空, 0显示0, 正数显示数字) + (document.querySelector('#inputHttpTimeout') as HTMLInputElement).value = httpTimeout >= 0 ? String(httpTimeout) : ''; + (document.querySelector('#inputStreamTimeout') as HTMLInputElement).value = streamTimeout >= 0 ? String(streamTimeout) : ''; + (document.querySelector('#inputMCPTimeout') as HTMLInputElement).value = mcpTimeout >= 0 ? String(mcpTimeout) : ''; + logInit(`超时设置: HTTP=${httpTimeout>=0?httpTimeout:30}s 流式=${streamTimeout>=0?streamTimeout:300}s MCP=${mcpTimeout>=0?mcpTimeout:60}s`); // ── Tool Calling 设置 ── const toolCallingEnabled = await db.getSetting('toolCallingEnabled', true); diff --git a/src/renderer/types.d.ts b/src/renderer/types.d.ts index a1e0697..e2aa888 100644 --- a/src/renderer/types.d.ts +++ b/src/renderer/types.d.ts @@ -220,6 +220,7 @@ export interface MetonaDesktopAPI { execute: (toolName: string, args: Record) => Promise; getConfig: () => Promise<{ allowedDirs: string[]; blockedDirs: string[] }>; setAllowedDirs: (dirs: string[]) => Promise; + setTimeouts: (timeouts: { http?: number; mcp?: number }) => Promise<{ success: boolean }>; }; notify: (title: string, body: string) => void; window: {