feat: 智能Agent接入前连通性/鉴权校验
- 前端技能市场「接入单个Agent」新增「测试连接」按钮,接入前必须校验通过 - 后端 POST /market/apps/verify-agent:dify 走 chat-messages 鉴权探测(trust_env=False 直连),n8n/coze 走 HEAD 可达性探测 - upload_app 对 agent 类型做服务端守卫,密钥无效/不可达直接 400 拒绝 - MarketApp 新增 platform 列(dify/n8n/coze),009 迁移幂等加列
This commit is contained in:
1 parent
b0bfba5c16
commit
d374d464e8
6 files changed
+209
-5
No files matched your search
@@ -1172,14 +1172,53 @@ const AgentConnectModal: React.FC<AgentConnectModalProps> = ({ onClose, onConnec
|
||||
const [endpoint, setEndpoint] = useState('');
|
||||
const [price, setPrice] = useState<number>(0);
|
||||
const [connecting, setConnecting] = useState(false);
|
||||
const [verifying, setVerifying] = useState(false);
|
||||
const [verifyMsg, setVerifyMsg] = useState<string>('');
|
||||
const [verifyOk, setVerifyOk] = useState<boolean | null>(null);
|
||||
|
||||
const handleConnect = () => {
|
||||
const runVerify = async (): Promise<boolean | null> => {
|
||||
if (!endpoint.trim() || !apiKey.trim()) {
|
||||
setVerifyMsg('请先填写 API Endpoint 与 API Key');
|
||||
setVerifyOk(false);
|
||||
return false;
|
||||
}
|
||||
setVerifying(true);
|
||||
setVerifyMsg('正在校验连通性与密钥...');
|
||||
setVerifyOk(null);
|
||||
try {
|
||||
const res: any = await marketAPI.verifyAgent({
|
||||
platform,
|
||||
endpoint: endpoint.trim(),
|
||||
api_key: apiKey.trim(),
|
||||
});
|
||||
if (res && res.code === 0 && res.data && res.data.ok) {
|
||||
setVerifyOk(true);
|
||||
setVerifyMsg('✓ ' + (res.data.detail || '校验通过'));
|
||||
return true;
|
||||
}
|
||||
setVerifyOk(false);
|
||||
setVerifyMsg('✗ ' + ((res && res.data && res.data.detail) || '校验未通过'));
|
||||
return false;
|
||||
} catch (e: any) {
|
||||
setVerifyOk(false);
|
||||
setVerifyMsg('✗ 校验请求失败:' + (e?.message || '网络错误'));
|
||||
return false;
|
||||
} finally {
|
||||
setVerifying(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConnect = async () => {
|
||||
if (!name.trim() || !endpoint.trim() || !apiKey.trim()) return;
|
||||
// 接入前必须先通过连通性 / 鉴权校验
|
||||
const ok = await runVerify();
|
||||
if (!ok) return;
|
||||
setConnecting(true);
|
||||
setTimeout(() => {
|
||||
try {
|
||||
await onConnect(platform, { apiKey: apiKey.trim(), endpoint: endpoint.trim() }, price, name.trim(), intro.trim());
|
||||
} finally {
|
||||
setConnecting(false);
|
||||
onConnect(platform, { apiKey: apiKey.trim(), endpoint: endpoint.trim() }, price, name.trim(), intro.trim());
|
||||
}, 800);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -1254,10 +1293,25 @@ const AgentConnectModal: React.FC<AgentConnectModalProps> = ({ onClose, onConnec
|
||||
/>
|
||||
<span className="hub-price-hint">用户对接的 Agent 是否收费由您决定;管理员导入默认免费且审核通过。</span>
|
||||
</div>
|
||||
<div className="form-section agent-verify-row">
|
||||
<button
|
||||
type="button"
|
||||
className="form-test-btn"
|
||||
onClick={runVerify}
|
||||
disabled={!endpoint.trim() || !apiKey.trim() || verifying}
|
||||
>
|
||||
{verifying ? '校验中...' : '测试连接'}
|
||||
</button>
|
||||
{verifyMsg && (
|
||||
<span className={`agent-verify-msg ${verifyOk === true ? 'ok' : verifyOk === false ? 'err' : ''}`}>
|
||||
{verifyMsg}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className="form-submit-btn"
|
||||
onClick={handleConnect}
|
||||
disabled={!name.trim() || !endpoint.trim() || !apiKey.trim() || connecting}
|
||||
disabled={!name.trim() || !endpoint.trim() || !apiKey.trim() || connecting || verifying}
|
||||
>
|
||||
{connecting ? '接入中...' : '接入 Agent'}
|
||||
</button>
|
||||
@@ -1393,6 +1447,7 @@ const MarketPage: React.FC = () => {
|
||||
source: 'user',
|
||||
agent_endpoint: config.endpoint || '',
|
||||
api_key: config.apiKey || '',
|
||||
platform: platformId || 'dify',
|
||||
});
|
||||
// 重新加载列表
|
||||
loadApps();
|
||||
|
||||
Reference in new issue
Block a user