fix: 修复多轮对话400/Provider通知反复弹出/浏览器环境隔离三大缺陷
1. 多轮对话第二次发消息 AI 不响应 (CRITICAL) handlers.ts: 保存 tool 结果消息到数据库,DeepSeek API 要求 assistant 有 tool_calls 时后续必须有对应 tool 结果消息 openai-format.ts: assistant 有 tool_calls 时 content 设为 null (API 规范,空字符串会导致 400) agent-store.ts: 前端加载历史时过滤 tool 消息,避免冗余卡片 2. Provider 切换通知每次发消息都弹出 main.ts: reloadAdapter 添加配置签名比较 (lastConfigSig),配置未变化时幂等返回 true,不再重建 adapter 或发 toast 3. 浏览器工具无环境隔离 browser-window-manager.ts: 独立 partition 隔离 Cookie/存储; 恢复 webSecurity,CORS 通过 webRequest 处理; setWindowOpenHandler 拦截 window.open; 并发互斥锁串行化 open 调用; destroy() 改用 win.destroy() + clearStorageData 清理残留
This commit is contained in:
+29
-6
@@ -262,14 +262,36 @@ async function initialize(): Promise<void> {
|
||||
confirmationHook.setToolDefs(toolRegistry.listAllTools());
|
||||
|
||||
// ===== 热重载 Adapter 回调(设置变更时触发)=====
|
||||
// 记录上次创建 adapter 时的配置快照,用于检测配置是否真的变化
|
||||
let lastProvider = configService.get<string>('llm.provider') ?? '';
|
||||
let lastConfigSig = JSON.stringify({
|
||||
provider: configService.get<string>('llm.provider') ?? '',
|
||||
model: configService.get<string>('llm.model') ?? '',
|
||||
apiKey: configService.get<string>('llm.apiKey') ?? '',
|
||||
baseURL: configService.get<string>('llm.baseURL') ?? '',
|
||||
});
|
||||
const reloadAdapter = (): boolean => {
|
||||
try {
|
||||
// 检测配置是否真的变化(避免每次发消息都重建 adapter 和弹 toast)
|
||||
const currentConfig = {
|
||||
provider: configService.get<string>('llm.provider') ?? '',
|
||||
model: configService.get<string>('llm.model') ?? '',
|
||||
apiKey: configService.get<string>('llm.apiKey') ?? '',
|
||||
baseURL: configService.get<string>('llm.baseURL') ?? '',
|
||||
};
|
||||
const currentSig = JSON.stringify(currentConfig);
|
||||
|
||||
// 配置未变化 — 幂等返回成功,不重建 adapter,不发通知
|
||||
if (currentSig === lastConfigSig) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 配置变化 — 重建 adapter
|
||||
const newAdapter = createAdapter();
|
||||
agentLoop.setAdapter(newAdapter);
|
||||
memoryConsolidator.setAdapter(newAdapter);
|
||||
// Provider 切换时同步 contextLength:仅 Ollama 使用 numCtx 作为有效上下文窗口
|
||||
const provider = configService.get<string>('llm.provider') ?? '';
|
||||
const provider = currentConfig.provider;
|
||||
if (provider === 'ollama') {
|
||||
const numCtx = configService.get<number>('ollama.numCtx');
|
||||
agentLoop.updateConfig({ contextLength: numCtx ?? undefined });
|
||||
@@ -277,7 +299,7 @@ async function initialize(): Promise<void> {
|
||||
agentLoop.updateConfig({ contextLength: undefined });
|
||||
}
|
||||
log.info(`[CONFIG] Adapter reloaded: provider=${provider}`);
|
||||
// 通知渲染进程 Provider 已切换(UI 显示 Toast + 系统消息)
|
||||
// 仅在 Provider 真正变化时通知渲染进程
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
if (lastProvider && lastProvider !== provider) {
|
||||
mainWindow.webContents.send('agent:providerSwitched', {
|
||||
@@ -286,13 +308,14 @@ async function initialize(): Promise<void> {
|
||||
reason: 'config_changed',
|
||||
sessionId: '',
|
||||
});
|
||||
mainWindow.webContents.send('toast:show', {
|
||||
type: 'success',
|
||||
message: `Provider 已切换: ${lastProvider} → ${provider}`,
|
||||
});
|
||||
}
|
||||
mainWindow.webContents.send('toast:show', {
|
||||
type: 'success',
|
||||
message: `Provider 已切换: ${lastProvider || '未知'} → ${provider}`,
|
||||
});
|
||||
}
|
||||
lastProvider = provider;
|
||||
lastConfigSig = currentSig;
|
||||
return true;
|
||||
} catch (err) {
|
||||
log.error(`[CONFIG] Failed to reload adapter: ${(err as Error).message}`);
|
||||
|
||||
Reference in New Issue
Block a user