feat: 重构MCP功能和AI服务提供者架构

This commit is contained in:
xiamuceer-j
2026-01-09 17:13:19 +08:00
parent f3c224261d
commit 77c5489ff8
49 changed files with 4763 additions and 4307 deletions
+162 -2
View File
@@ -1,8 +1,8 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Card, Form, Input, Button, Select, Slider, InputNumber, message, Space, Typography, Spin, Modal, Alert, Grid, Tabs, List, Tag, Popconfirm, Empty, Row, Col } from 'antd';
import { SettingOutlined, SaveOutlined, DeleteOutlined, ReloadOutlined, ArrowLeftOutlined, InfoCircleOutlined, CheckCircleOutlined, CloseCircleOutlined, ThunderboltOutlined, PlusOutlined, EditOutlined, CopyOutlined } from '@ant-design/icons';
import { settingsApi } from '../services/api';
import { SettingOutlined, SaveOutlined, DeleteOutlined, ReloadOutlined, ArrowLeftOutlined, InfoCircleOutlined, CheckCircleOutlined, CloseCircleOutlined, ThunderboltOutlined, PlusOutlined, EditOutlined, CopyOutlined, WarningOutlined } from '@ant-design/icons';
import { settingsApi, mcpPluginApi } from '../services/api';
import type { SettingsUpdate, APIKeyPreset, PresetCreateRequest, APIKeyPresetConfig } from '../types';
const { Title, Text } = Typography;
@@ -95,10 +95,86 @@ export default function SettingsPage() {
const handleSave = async (values: SettingsUpdate) => {
setLoading(true);
try {
// 检查是否与 MCP 缓存的配置不一致
const verifiedConfigStr = localStorage.getItem('mcp_verified_config');
let configChanged = false;
if (verifiedConfigStr) {
try {
const verifiedConfig = JSON.parse(verifiedConfigStr);
configChanged =
verifiedConfig.provider !== values.api_provider ||
verifiedConfig.baseUrl !== values.api_base_url ||
verifiedConfig.model !== values.llm_model;
} catch (e) {
console.error('Failed to parse verified config:', e);
}
}
await settingsApi.saveSettings(values);
message.success('设置已保存');
setHasSettings(true);
setIsDefaultSettings(false);
// 如果配置发生变化,需要处理 MCP 插件
if (configChanged) {
// 清除 MCP 验证缓存
localStorage.removeItem('mcp_verified_config');
// 检查并禁用所有 MCP 插件
try {
const plugins = await mcpPluginApi.getPlugins();
const activePlugins = plugins.filter(p => p.enabled);
if (activePlugins.length > 0) {
// 禁用所有插件
message.loading({ content: '正在禁用 MCP 插件...', key: 'disable_mcp' });
await Promise.all(activePlugins.map(p => mcpPluginApi.togglePlugin(p.id, false)));
message.success({ content: '已禁用所有 MCP 插件', key: 'disable_mcp' });
// 显示提示弹窗
modal.warning({
title: (
<Space>
<WarningOutlined style={{ color: '#faad14' }} />
<span>API </span>
</Space>
),
centered: true,
content: (
<div style={{ padding: '8px 0' }}>
<Alert
message="检测到您修改了 API 配置(提供商、地址或模型),为确保 MCP 插件正常工作,系统已自动禁用所有插件。"
type="warning"
showIcon
style={{ marginBottom: 16 }}
/>
<div style={{
padding: 12,
background: 'var(--color-info-bg)',
border: '1px solid var(--color-info-border)',
borderRadius: 8
}}>
<Text strong style={{ display: 'block', marginBottom: 8 }}></Text>
<ol style={{ margin: 0, paddingLeft: 20, fontSize: 13 }}>
<li> MCP </li>
<li>"模型能力检查"</li>
<li> Function Calling </li>
</ol>
</div>
</div>
),
okText: '前往 MCP 页面',
cancelText: '稍后处理',
onOk: () => {
navigate('/mcp-plugins');
},
});
}
} catch (err) {
console.error('Failed to disable MCP plugins:', err);
}
}
} catch (error) {
message.error('保存设置失败');
} finally {
@@ -348,10 +424,94 @@ export default function SettingsPage() {
const handlePresetActivate = async (presetId: string, presetName: string) => {
try {
// 获取预设配置用于比较
const preset = presets.find(p => p.id === presetId);
await settingsApi.activatePreset(presetId);
message.success(`已激活预设: ${presetName}`);
loadPresets();
loadSettings(); // 重新加载当前配置
// 检查是否与 MCP 缓存的配置不一致
if (preset) {
const verifiedConfigStr = localStorage.getItem('mcp_verified_config');
let configChanged = false;
if (verifiedConfigStr) {
try {
const verifiedConfig = JSON.parse(verifiedConfigStr);
configChanged =
verifiedConfig.provider !== preset.config.api_provider ||
verifiedConfig.baseUrl !== preset.config.api_base_url ||
verifiedConfig.model !== preset.config.llm_model;
} catch (e) {
console.error('Failed to parse verified config:', e);
configChanged = true; // 解析失败也视为配置变化
}
} else {
// 没有缓存的配置,如果有启用的插件也需要处理
configChanged = true;
}
if (configChanged) {
// 清除 MCP 验证缓存
localStorage.removeItem('mcp_verified_config');
// 检查并禁用所有 MCP 插件
try {
const plugins = await mcpPluginApi.getPlugins();
const activePlugins = plugins.filter(p => p.enabled);
if (activePlugins.length > 0) {
// 禁用所有插件
message.loading({ content: '正在禁用 MCP 插件...', key: 'disable_mcp' });
await Promise.all(activePlugins.map(p => mcpPluginApi.togglePlugin(p.id, false)));
message.success({ content: '已禁用所有 MCP 插件', key: 'disable_mcp' });
// 显示提示弹窗
modal.warning({
title: (
<Space>
<WarningOutlined style={{ color: '#faad14' }} />
<span>API </span>
</Space>
),
centered: true,
content: (
<div style={{ padding: '8px 0' }}>
<Alert
message={`切换到预设「${presetName}」后,API 配置发生了变化。为确保 MCP 插件正常工作,系统已自动禁用所有插件。`}
type="warning"
showIcon
style={{ marginBottom: 16 }}
/>
<div style={{
padding: 12,
background: 'var(--color-info-bg)',
border: '1px solid var(--color-info-border)',
borderRadius: 8
}}>
<Text strong style={{ display: 'block', marginBottom: 8 }}></Text>
<ol style={{ margin: 0, paddingLeft: 20, fontSize: 13 }}>
<li> MCP </li>
<li>"模型能力检查"</li>
<li> Function Calling </li>
</ol>
</div>
</div>
),
okText: '前往 MCP 页面',
cancelText: '稍后处理',
onOk: () => {
navigate('/mcp-plugins');
},
});
}
} catch (err) {
console.error('Failed to disable MCP plugins:', err);
}
}
}
} catch (error) {
message.error('激活失败');
console.error(error);