前台8项体验修复: 知识库上传自动刷新; 资产PDF归类; Token驾驶舱媒体统计; AI模糊意图澄清选择; ChatPage增加MCP/附件上传/语音; 技能市场安装态修复+清理演示数据; MCP协议应用改名MCP应用; Agent单应用接入(名称/介绍/API Key)
This commit is contained in:
1 parent
463824480b
commit
bc2899ed09
11 files changed
+945
-154
No files matched your search
@@ -173,7 +173,7 @@ function renderAppIconLarge(app: MarketApp): React.ReactNode {
|
||||
const typeLabels: Record<AppType, string> = {
|
||||
skill: 'Skills工具',
|
||||
agent: '智能Agent',
|
||||
mcp: 'MCP协议应用',
|
||||
mcp: 'MCP应用',
|
||||
};
|
||||
|
||||
const typeIcons: Record<AppType, React.ReactNode> = {
|
||||
@@ -1158,122 +1158,109 @@ const mcpClient = new MCPClient({
|
||||
);
|
||||
};
|
||||
|
||||
// ===== Agent Platform Connect Modal (修改4) =====
|
||||
// ===== Agent 单接入 Modal(修改8:以单个Agent方式接入,含名称/介绍) =====
|
||||
interface AgentConnectModalProps {
|
||||
onClose: () => void;
|
||||
onConnect: (platformId: string, config: Record<string, string>, price?: number) => void;
|
||||
onConnect: (platformId: string, config: Record<string, string>, price?: number, name?: string, description?: string) => void;
|
||||
}
|
||||
|
||||
const AgentConnectModal: React.FC<AgentConnectModalProps> = ({ onClose, onConnect }) => {
|
||||
const [selectedPlatform, setSelectedPlatform] = useState<string | null>(null);
|
||||
const [platform, setPlatform] = useState<string>('dify');
|
||||
const [name, setName] = useState('');
|
||||
const [intro, setIntro] = useState('');
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [endpoint, setEndpoint] = useState('');
|
||||
const [price, setPrice] = useState<number>(0);
|
||||
const [connecting, setConnecting] = useState(false);
|
||||
const [connected, setConnected] = useState<string | null>(null);
|
||||
|
||||
const handleConnect = () => {
|
||||
if (!selectedPlatform || !apiKey.trim()) return;
|
||||
if (!name.trim() || !endpoint.trim() || !apiKey.trim()) return;
|
||||
setConnecting(true);
|
||||
setTimeout(() => {
|
||||
setConnecting(false);
|
||||
setConnected(selectedPlatform);
|
||||
onConnect(selectedPlatform, { apiKey: apiKey.trim(), endpoint: endpoint.trim() }, price);
|
||||
}, 1500);
|
||||
onConnect(platform, { apiKey: apiKey.trim(), endpoint: endpoint.trim() }, price, name.trim(), intro.trim());
|
||||
}, 800);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="market-modal-overlay" onClick={onClose}>
|
||||
<div className="market-modal agent-connect-modal" onClick={e => e.stopPropagation()}>
|
||||
<div className="market-modal-header">
|
||||
<h2>对接外部Agent平台</h2>
|
||||
<h2>接入单个 Agent</h2>
|
||||
<button className="market-modal-close" onClick={onClose}><CloseIcon /></button>
|
||||
</div>
|
||||
<div className="market-modal-body">
|
||||
<p className="hub-import-desc">
|
||||
将外部平台的Agent接入AIFlow应用市场,实现跨平台的Agent管理与调度。
|
||||
以单个 Agent 方式接入(例如 Dify 中每个 Agent 都有独立的访问地址与密钥)。请填写该 Agent 的名称、介绍及连接信息。
|
||||
</p>
|
||||
|
||||
{!selectedPlatform ? (
|
||||
<div className="agent-platforms">
|
||||
<div className="form-section">
|
||||
<label className="form-label">所属平台</label>
|
||||
<select className="form-input" value={platform} onChange={e => setPlatform(e.target.value)}>
|
||||
{agentPlatforms.map(p => (
|
||||
<div
|
||||
key={p.id}
|
||||
className={`agent-platform-card ${connected === p.id ? 'connected' : ''}`}
|
||||
onClick={() => { setSelectedPlatform(p.id); setEndpoint(p.id === 'dify' ? 'https://api.dify.ai/v1' : p.id === 'n8n' ? 'https://n8n.example.com/api/v1' : 'https://api.coze.cn/v1'); }}
|
||||
>
|
||||
<div className="agent-platform-icon">
|
||||
<ApiIcon />
|
||||
</div>
|
||||
<div className="agent-platform-info">
|
||||
<strong>{p.name}</strong>
|
||||
<span>{p.description}</span>
|
||||
</div>
|
||||
{connected === p.id ? (
|
||||
<span className="connected-badge"><CheckCircleIcon /> 已连接</span>
|
||||
) : (
|
||||
<span className="connect-indicator">配置</span>
|
||||
)}
|
||||
</div>
|
||||
<option key={p.id} value={p.id}>{p.name}</option>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="agent-config-form">
|
||||
<button className="back-btn" onClick={() => setSelectedPlatform(null)}>
|
||||
← 返回选择
|
||||
</button>
|
||||
<div className="form-section">
|
||||
<label className="form-label">平台</label>
|
||||
<input type="text" className="form-input" value={agentPlatforms.find(p => p.id === selectedPlatform)?.name || ''} disabled />
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">API Key <span className="required">*</span></label>
|
||||
<input
|
||||
type="password"
|
||||
className="form-input"
|
||||
placeholder="请输入API Key"
|
||||
value={apiKey}
|
||||
onChange={e => setApiKey(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">API Endpoint</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-input"
|
||||
placeholder="https://..."
|
||||
value={endpoint}
|
||||
onChange={e => setEndpoint(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">定价(元)</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.01"
|
||||
className="form-input"
|
||||
placeholder="0 为免费"
|
||||
value={price}
|
||||
onChange={e => setPrice(parseFloat(e.target.value) || 0)}
|
||||
/>
|
||||
<span className="hub-price-hint">用户对接的Agent:是否收费由您决定;管理员导入默认免费且审核通过。</span>
|
||||
</div>
|
||||
<button
|
||||
className="form-submit-btn"
|
||||
onClick={handleConnect}
|
||||
disabled={!apiKey.trim() || connecting}
|
||||
>
|
||||
{connecting ? '连接验证中...' : '连接并同步Agent'}
|
||||
</button>
|
||||
{connecting && (
|
||||
<div className="hub-importing-status">
|
||||
<div className="audit-spinner small" />
|
||||
<span>正在验证连接并同步Agent列表...</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">Agent 名称 <span className="required">*</span></label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-input"
|
||||
placeholder="例如:我的客服 Agent"
|
||||
value={name}
|
||||
onChange={e => setName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">Agent 介绍</label>
|
||||
<textarea
|
||||
className="form-input"
|
||||
rows={3}
|
||||
placeholder="简要描述该 Agent 的能力与用途"
|
||||
value={intro}
|
||||
onChange={e => setIntro(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">API Endpoint(该 Agent 专属地址)<span className="required">*</span></label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-input"
|
||||
placeholder="https://..."
|
||||
value={endpoint}
|
||||
onChange={e => setEndpoint(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">API Key <span className="required">*</span></label>
|
||||
<input
|
||||
type="password"
|
||||
className="form-input"
|
||||
placeholder="请输入该 Agent 的 API Key"
|
||||
value={apiKey}
|
||||
onChange={e => setApiKey(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label className="form-label">定价(元)</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.01"
|
||||
className="form-input"
|
||||
placeholder="0 为免费"
|
||||
value={price}
|
||||
onChange={e => setPrice(parseFloat(e.target.value) || 0)}
|
||||
/>
|
||||
<span className="hub-price-hint">用户对接的 Agent 是否收费由您决定;管理员导入默认免费且审核通过。</span>
|
||||
</div>
|
||||
<button
|
||||
className="form-submit-btn"
|
||||
onClick={handleConnect}
|
||||
disabled={!name.trim() || !endpoint.trim() || !apiKey.trim() || connecting}
|
||||
>
|
||||
{connecting ? '接入中...' : '接入 Agent'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1344,7 +1331,7 @@ const MarketPage: React.FC = () => {
|
||||
{ key: 'all', label: '全部' },
|
||||
{ key: 'skill', label: 'Skills工具' },
|
||||
{ key: 'agent', label: '智能Agent' },
|
||||
{ key: 'mcp', label: 'MCP协议应用' },
|
||||
{ key: 'mcp', label: 'MCP应用' },
|
||||
];
|
||||
|
||||
// Handle create tool - 调用后端 API 创建应用
|
||||
@@ -1388,20 +1375,24 @@ const MarketPage: React.FC = () => {
|
||||
setShowHubImport(null);
|
||||
};
|
||||
|
||||
// Handle agent connect - 调用后端 API 创建应用
|
||||
const handleAgentConnect = async (platformId: string, config: Record<string, string>, price?: number) => {
|
||||
// Handle agent connect - 调用后端 API 创建应用(单个Agent方式接入)
|
||||
const handleAgentConnect = async (platformId: string, config: Record<string, string>, price?: number, name?: string, description?: string) => {
|
||||
const platform = agentPlatforms.find(p => p.id === platformId);
|
||||
if (!platform) return;
|
||||
const finalName = (name && name.trim()) ? name.trim() : `${platform?.name || '外部'} Agent`;
|
||||
const finalDesc = (description && description.trim())
|
||||
? description.trim()
|
||||
: `从 ${platform?.name || '外部平台'} 对接导入的智能Agent`;
|
||||
try {
|
||||
await marketAPI.createApp({
|
||||
name: `${platform.name} Agent`,
|
||||
name: finalName,
|
||||
type: 'agent',
|
||||
description: `从 ${platform.name} 对接导入的智能Agent`,
|
||||
description: finalDesc,
|
||||
price: price || 0,
|
||||
is_member_free: (price || 0) === 0,
|
||||
join_promotion: false,
|
||||
source: 'user',
|
||||
agent_endpoint: config.endpoint || '',
|
||||
api_key: config.apiKey || '',
|
||||
});
|
||||
// 重新加载列表
|
||||
loadApps();
|
||||
|
||||
Reference in new issue
Block a user