feat: 完成 Agent MCP 对接
- 增加 MCP 连接类型、环境检测接口和容器运行环境支持 - 将 Agent 编排改为绑定整体 MCP 并编译为 runtime McpSpec - 优化 MCP 工具展示、审批、草稿试运行和画布回显稳定性
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
/* cspell:ignore tryit */
|
||||
import type {AgentCapabilityKind, AgentOption, AgentValidationIssue,} from './types';
|
||||
import type {
|
||||
AgentCapabilityKind,
|
||||
AgentOption,
|
||||
AgentValidationIssue,
|
||||
} from './types';
|
||||
|
||||
import {computed, onMounted, ref} from 'vue';
|
||||
import {useRoute, useRouter} from 'vue-router';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||
import {tryit} from 'radash';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { tryit } from 'radash';
|
||||
|
||||
import {api} from '#/api/request';
|
||||
import { api } from '#/api/request';
|
||||
import {
|
||||
canAiResourceOffline,
|
||||
canAiResourcePublish,
|
||||
@@ -30,7 +34,7 @@ import {
|
||||
import AgentStudioCanvas from './components/agent-studio/AgentStudioCanvas.vue';
|
||||
import AgentCommandBar from './components/AgentCommandBar.vue';
|
||||
import AgentInspectorPanel from './components/AgentInspectorPanel.vue';
|
||||
import {useAgentDesignerState} from './composables/useAgentDesignerState';
|
||||
import { useAgentDesignerState } from './composables/useAgentDesignerState';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -62,6 +66,7 @@ const models = ref<AgentOption[]>([]);
|
||||
const knowledges = ref<AgentOption[]>([]);
|
||||
const workflows = ref<AgentOption[]>([]);
|
||||
const pluginTools = ref<AgentOption[]>([]);
|
||||
const mcps = ref<AgentOption[]>([]);
|
||||
|
||||
const isNew = computed(() => String(route.params.id || '') === 'new');
|
||||
const publishText = computed(() => {
|
||||
@@ -132,6 +137,21 @@ async function loadAgent() {
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshAgentLifecycleState() {
|
||||
if (!state.agent.id) return;
|
||||
const [, res] = await tryit(getAgentDetail)(String(state.agent.id));
|
||||
if (res?.errorCode !== 0 || !res.data) {
|
||||
return;
|
||||
}
|
||||
const agentState = { ...res.data };
|
||||
delete agentState.knowledgeBindings;
|
||||
delete agentState.toolBindings;
|
||||
state.agent = {
|
||||
...state.agent,
|
||||
...agentState,
|
||||
};
|
||||
}
|
||||
|
||||
function hasNavTitle() {
|
||||
const navTitle = Array.isArray(route.query.navTitle)
|
||||
? route.query.navTitle[0]
|
||||
@@ -172,7 +192,7 @@ function syncNavTitle(title: string, options: { force?: boolean } = {}) {
|
||||
}
|
||||
|
||||
async function loadOptions() {
|
||||
const [categoryRes, modelRes, knowledgeRes, workflowRes, pluginRes] =
|
||||
const [categoryRes, modelRes, knowledgeRes, workflowRes, pluginRes, mcpRes] =
|
||||
await Promise.all([
|
||||
api.get('/api/v1/agentCategory/visibleList', {
|
||||
params: { sortKey: 'sortNo', sortType: 'asc' },
|
||||
@@ -185,6 +205,9 @@ async function loadOptions() {
|
||||
api.get('/api/v1/plugin/pageByCategory', {
|
||||
params: { pageNumber: 1, pageSize: 200, category: 0 },
|
||||
}),
|
||||
api.get('/api/v1/mcp/pageTools', {
|
||||
params: { pageNumber: 1, pageSize: 200, status: 1 },
|
||||
}),
|
||||
]);
|
||||
|
||||
categories.value = (categoryRes.data || []).map((item: any) => ({
|
||||
@@ -212,6 +235,7 @@ async function loadOptions() {
|
||||
pluginTools.value = flattenPluginTools(
|
||||
pluginRes.data?.records || pluginRes.data || [],
|
||||
);
|
||||
mcps.value = mapMcpOptions(mcpRes.data?.records || mcpRes.data || []);
|
||||
}
|
||||
|
||||
function flattenPluginTools(list: any[]): AgentOption[] {
|
||||
@@ -229,6 +253,22 @@ function flattenPluginTools(list: any[]): AgentOption[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
function mapMcpOptions(list: any[]): AgentOption[] {
|
||||
return list.map((mcp) => ({
|
||||
label: mcp.title || mcp.name || 'MCP',
|
||||
value: String(mcp.id),
|
||||
raw: {
|
||||
...mcp,
|
||||
id: mcp.id,
|
||||
mcpId: mcp.id,
|
||||
mcpTitle: mcp.title || mcp.name,
|
||||
title: mcp.title || mcp.name,
|
||||
tools: Array.isArray(mcp.tools) ? mcp.tools : [],
|
||||
approvalRequired: Boolean(mcp.approvalRequired),
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
async function handleAdd(kind: AgentCapabilityKind) {
|
||||
if (kind === 'knowledge') {
|
||||
addKnowledgeNode();
|
||||
@@ -331,7 +371,7 @@ async function handlePublish() {
|
||||
const res = await submitAgentPublishApproval(String(state.agent.id));
|
||||
if (res.errorCode === 0) {
|
||||
ElMessage.success(res.message || '已提交');
|
||||
await loadAgent();
|
||||
await refreshAgentLifecycleState();
|
||||
}
|
||||
} finally {
|
||||
publishLoading.value = false;
|
||||
@@ -358,7 +398,7 @@ async function handleOffline() {
|
||||
const res = await submitAgentOfflineApproval(String(state.agent.id));
|
||||
if (res.errorCode === 0) {
|
||||
ElMessage.success(res.message || '已提交');
|
||||
await loadAgent();
|
||||
await refreshAgentLifecycleState();
|
||||
}
|
||||
} finally {
|
||||
offlineLoading.value = false;
|
||||
@@ -380,7 +420,10 @@ function handleCloseTryout() {
|
||||
<AgentStudioCanvas
|
||||
:state="state"
|
||||
:knowledge-options="knowledges"
|
||||
:mcp-options="mcps"
|
||||
:plugin-options="pluginTools"
|
||||
:selected-node-id="state.selectedNodeId"
|
||||
:workflow-options="workflows"
|
||||
@select="handleSelectNode"
|
||||
/>
|
||||
<AgentInspectorPanel
|
||||
@@ -390,6 +433,7 @@ function handleCloseTryout() {
|
||||
:knowledges="knowledges"
|
||||
:workflows="workflows"
|
||||
:plugin-tools="pluginTools"
|
||||
:mcps="mcps"
|
||||
:issues="issues"
|
||||
@change="markDirty"
|
||||
@remove-capability="removeSelectedCapability"
|
||||
|
||||
Reference in New Issue
Block a user