fix: 超时设置0值(禁用)无法保存的bug

- 保存值改用-1表示默认, 0表示禁用, 正数表示自定义秒数
- 修复parseSec区分空字符串和0值
- loadTimeoutSettings/main.ts初始化同步更新判断逻辑
- 补全types.d.ts中setTimeouts类型声明
This commit is contained in:
thzxx
2026-06-10 09:54:20 +08:00
parent 9559390d4d
commit 0489952ceb
3 changed files with 39 additions and 37 deletions
+25 -22
View File
@@ -73,30 +73,33 @@ export function initSettingsModal(): void {
const db = state.get<ChatDB | null>(KEYS.DB); const db = state.get<ChatDB | null>(KEYS.DB);
const bridge = window.metonaDesktop; const bridge = window.metonaDesktop;
// 辅助:解析输入值,空→-1(默认),数字→该值(含0=禁用)
const parseSec = (val: string): number => (val !== '' ? parseInt(val) : -1);
// HTTP 超时(秒→毫秒) // HTTP 超时(秒→毫秒)
const httpVal = inputHttpTimeout.value.trim(); const httpSec = parseSec(inputHttpTimeout.value.trim());
const httpSec = httpVal ? parseInt(httpVal) : 0; const httpMs = httpSec >= 0 ? httpSec * 1000 : 30_000;
if (db) await db.saveSetting('httpTimeout', httpSec > 0 ? httpSec : 0); if (db) await db.saveSetting('httpTimeout', httpSec);
if (bridge?.tool?.setTimeouts) { 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 = parseSec(inputStreamTimeout.value.trim());
const streamSec = streamVal ? parseInt(streamVal) : 0; const streamMs = streamSec >= 0 ? streamSec * 1000 : 300_000;
state.set('streamTimeout', streamSec > 0 ? streamSec * 1000 : 300_000); state.set('streamTimeout', streamMs);
if (db) await db.saveSetting('streamTimeout', streamSec > 0 ? streamSec : 0); if (db) await db.saveSetting('streamTimeout', streamSec);
logInfo('流式超时', streamSec > 0 ? `${streamSec}s` : '默认(300s)'); logInfo('流式超时', streamSec >= 0 ? (streamSec === 0 ? '已禁用' : `${streamSec}s`) : '默认(300s)');
// MCP 超时(秒→毫秒) // MCP 超时(秒→毫秒)
const mcpVal = inputMCPTimeout.value.trim(); const mcpSec = parseSec(inputMCPTimeout.value.trim());
const mcpSec = mcpVal ? parseInt(mcpVal) : 0; const mcpMs = mcpSec >= 0 ? mcpSec * 1000 : 60_000;
if (db) await db.saveSetting('mcpTimeout', mcpSec > 0 ? mcpSec : 0); if (db) await db.saveSetting('mcpTimeout', mcpSec);
if (bridge?.tool?.setTimeouts) { 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); const saveHttpTimeout = debounce(applyTimeouts, 500);
@@ -309,22 +312,22 @@ export function closeSettingsModal(): void {
settingsModalEl.style.display = 'none'; settingsModalEl.style.display = 'none';
} }
/** 加载已保存的超时设置到输入框 */ /** 加载已保存的超时设置到输入框:-1=默认(显示空), 0=禁用, 正数=自定义 */
async function loadTimeoutSettings(): Promise<void> { async function loadTimeoutSettings(): Promise<void> {
const db = state.get<ChatDB | null>(KEYS.DB); const db = state.get<ChatDB | null>(KEYS.DB);
if (!db) return; if (!db) return;
const httpTimeout = await db.getSetting<number>('httpTimeout', 0); const httpTimeout = await db.getSetting<number>('httpTimeout', -1);
const streamTimeout = await db.getSetting<number>('streamTimeout', 0); const streamTimeout = await db.getSetting<number>('streamTimeout', -1);
const mcpTimeout = await db.getSetting<number>('mcpTimeout', 0); const mcpTimeout = await db.getSetting<number>('mcpTimeout', -1);
const inputHttp = document.querySelector('#inputHttpTimeout') as HTMLInputElement; const inputHttp = document.querySelector('#inputHttpTimeout') as HTMLInputElement;
const inputStream = document.querySelector('#inputStreamTimeout') as HTMLInputElement; const inputStream = document.querySelector('#inputStreamTimeout') as HTMLInputElement;
const inputMCP = document.querySelector('#inputMCPTimeout') as HTMLInputElement; const inputMCP = document.querySelector('#inputMCPTimeout') as HTMLInputElement;
if (inputHttp) inputHttp.value = httpTimeout > 0 ? String(httpTimeout) : ''; if (inputHttp) inputHttp.value = httpTimeout >= 0 ? String(httpTimeout) : '';
if (inputStream) inputStream.value = streamTimeout > 0 ? String(streamTimeout) : ''; if (inputStream) inputStream.value = streamTimeout >= 0 ? String(streamTimeout) : '';
if (inputMCP) inputMCP.value = mcpTimeout > 0 ? String(mcpTimeout) : ''; if (inputMCP) inputMCP.value = mcpTimeout >= 0 ? String(mcpTimeout) : '';
} }
async function exportAllSessions(): Promise<void> { async function exportAllSessions(): Promise<void> {
+13 -15
View File
@@ -362,30 +362,28 @@ async function init(): Promise<void> {
state.set('maxTurns', maxTurns); state.set('maxTurns', maxTurns);
(document.querySelector('#inputMaxTurns') as HTMLInputElement).value = String(maxTurns); (document.querySelector('#inputMaxTurns') as HTMLInputElement).value = String(maxTurns);
// ── v5.2 超时设置 ── // ── v5.2 超时设置:-1=默认, 0=禁用, 正数=自定义 ──
const httpTimeout = await db.getSetting<number>('httpTimeout', 0); const httpTimeout = await db.getSetting<number>('httpTimeout', -1);
const streamTimeout = await db.getSetting<number>('streamTimeout', 0); const streamTimeout = await db.getSetting<number>('streamTimeout', -1);
const mcpTimeout = await db.getSetting<number>('mcpTimeout', 0); const mcpTimeout = await db.getSetting<number>('mcpTimeout', -1);
// 应用流式超时到 stateagent-engine 读取) // 应用流式超时到 stateagent-engine 读取0=禁用
state.set('streamTimeout', streamTimeout > 0 ? streamTimeout * 1000 : 300_000); state.set('streamTimeout', streamTimeout >= 0 ? streamTimeout * 1000 : 300_000);
// 应用 HTTP 和 MCP 超时到主进程 // 应用 HTTP 和 MCP 超时到主进程
const bridge = window.metonaDesktop; const bridge = window.metonaDesktop;
if (bridge?.tool?.setTimeouts) { if (bridge?.tool?.setTimeouts) {
await bridge.tool.setTimeouts({ await bridge.tool.setTimeouts({
http: httpTimeout > 0 ? httpTimeout * 1000 : 30_000, http: httpTimeout >= 0 ? httpTimeout * 1000 : 30_000,
mcp: mcpTimeout > 0 ? mcpTimeout * 1000 : 60_000, mcp: mcpTimeout >= 0 ? mcpTimeout * 1000 : 60_000,
}); });
} }
// 恢复输入框显示 // 恢复输入框显示(-1显示空, 0显示0, 正数显示数字)
if (document.querySelector('#inputHttpTimeout')) { (document.querySelector('#inputHttpTimeout') as HTMLInputElement).value = httpTimeout >= 0 ? String(httpTimeout) : '';
(document.querySelector('#inputHttpTimeout') as HTMLInputElement).value = httpTimeout > 0 ? String(httpTimeout) : ''; (document.querySelector('#inputStreamTimeout') as HTMLInputElement).value = streamTimeout >= 0 ? String(streamTimeout) : '';
(document.querySelector('#inputStreamTimeout') as HTMLInputElement).value = streamTimeout > 0 ? String(streamTimeout) : ''; (document.querySelector('#inputMCPTimeout') as HTMLInputElement).value = mcpTimeout >= 0 ? String(mcpTimeout) : '';
(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`);
}
logInit(`超时设置: HTTP=${httpTimeout||30}s 流式=${streamTimeout||300}s MCP=${mcpTimeout||60}s`);
// ── Tool Calling 设置 ── // ── Tool Calling 设置 ──
const toolCallingEnabled = await db.getSetting('toolCallingEnabled', true); const toolCallingEnabled = await db.getSetting('toolCallingEnabled', true);
+1
View File
@@ -220,6 +220,7 @@ export interface MetonaDesktopAPI {
execute: (toolName: string, args: Record<string, unknown>) => Promise<ToolResult>; execute: (toolName: string, args: Record<string, unknown>) => Promise<ToolResult>;
getConfig: () => Promise<{ allowedDirs: string[]; blockedDirs: string[] }>; getConfig: () => Promise<{ allowedDirs: string[]; blockedDirs: string[] }>;
setAllowedDirs: (dirs: string[]) => Promise<void>; setAllowedDirs: (dirs: string[]) => Promise<void>;
setTimeouts: (timeouts: { http?: number; mcp?: number }) => Promise<{ success: boolean }>;
}; };
notify: (title: string, body: string) => void; notify: (title: string, body: string) => void;
window: { window: {