diff --git a/electron/ipc/handlers.ts b/electron/ipc/handlers.ts index 6748b0e..feb3a7d 100644 --- a/electron/ipc/handlers.ts +++ b/electron/ipc/handlers.ts @@ -52,6 +52,9 @@ export function registerAllIPCHandlers( ipcMain.handle('agent:sendMessage', async (_event, userMessage: MetonaMessage, sessionId: string) => { log.info('[AGENT] sendMessage:', sessionId, userMessage.content.slice(0, 80)); + // 发送消息前确保 Adapter 使用最新配置(防止 config:set 中间状态导致 reload 失败) + reloadAdapter(); + // TRACE 层:开始录制 sessionRecorder.startRecording(sessionId); diff --git a/electron/main.ts b/electron/main.ts index 5788589..379900f 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -230,15 +230,20 @@ async function initialize(): Promise { // ===== 热重载 Adapter 回调(设置变更时触发)===== const reloadAdapter = () => { - const newAdapter = createAdapter(); - agentLoop.setAdapter(newAdapter); - // Provider 切换时同步 contextLength:仅 Ollama 使用 numCtx 作为有效上下文窗口 - const provider = configService.get('llm.provider') ?? ''; - if (provider === 'ollama') { - const numCtx = configService.get('ollama.numCtx'); - agentLoop.updateConfig({ contextLength: numCtx ?? undefined }); - } else { - agentLoop.updateConfig({ contextLength: undefined }); + try { + const newAdapter = createAdapter(); + agentLoop.setAdapter(newAdapter); + // Provider 切换时同步 contextLength:仅 Ollama 使用 numCtx 作为有效上下文窗口 + const provider = configService.get('llm.provider') ?? ''; + if (provider === 'ollama') { + const numCtx = configService.get('ollama.numCtx'); + agentLoop.updateConfig({ contextLength: numCtx ?? undefined }); + } else { + agentLoop.updateConfig({ contextLength: undefined }); + } + log.info(`[CONFIG] Adapter reloaded: provider=${provider}`); + } catch (err) { + log.error(`[CONFIG] Failed to reload adapter: ${(err as Error).message}`); } }; diff --git a/src/components/settings/SettingsModal.tsx b/src/components/settings/SettingsModal.tsx index ea844b2..81d1b9a 100644 --- a/src/components/settings/SettingsModal.tsx +++ b/src/components/settings/SettingsModal.tsx @@ -118,11 +118,26 @@ function LLMSettings() { } }, [provider, numCtx]); + // 切换 Provider 时自动填充默认 URL + 清空 Ollama 的 apiKey + const handleProviderChange = (newProvider: string) => { + setProvider(newProvider); + // Ollama 不需要 API Key,切换到 Ollama 时清空旧 key + if (newProvider === 'ollama' && apiKey) { + setApiKey(''); + } + // 自动填充默认 URL(仅在 URL 为空或与旧 provider 默认 URL 匹配时) + const currentUrl = baseURL.trim(); + const isDefaultUrl = Object.values(PROVIDER_URLS).includes(currentUrl); + if (isDefaultUrl || !currentUrl) { + setBaseURL(PROVIDER_URLS[newProvider] ?? ''); + } + }; + return ( LLM 配置 Provider - handleProviderChange(e.target.value)}> DeepSeek Agnes AI Ollama (本地) @@ -130,9 +145,11 @@ function LLMSettings() { setBaseURL(e.target.value)} placeholder="如 https://api.deepseek.com" /> setModel(e.target.value)} placeholder="如 deepseek-v4-pro、qwen3:latest" /> - setApiKey(e.target.value)} placeholder="sk-...(本地模型可留空)" - slotProps={{ input: { endAdornment: setShowKey(!showKey)}>{showKey ? : } } }} - /> + {provider !== 'ollama' && ( + setApiKey(e.target.value)} placeholder="sk-..." + slotProps={{ input: { endAdornment: setShowKey(!showKey)}>{showKey ? : } } }} + /> + )} {provider === 'ollama' && (