feat: 完成 Agent MCP 对接
- 增加 MCP 连接类型、环境检测接口和容器运行环境支持 - 将 Agent 编排改为绑定整体 MCP 并编译为 runtime McpSpec - 优化 MCP 工具展示、审批、草稿试运行和画布回显稳定性
This commit is contained in:
@@ -12,7 +12,7 @@ import type {
|
||||
AgentToolBinding,
|
||||
} from '../../types';
|
||||
|
||||
import {computed} from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const BASE_NODE_ID = 'agent-base';
|
||||
const BASE_POSITION = { x: 430, y: 260 };
|
||||
@@ -57,19 +57,66 @@ function buildKnowledgeTitle(
|
||||
);
|
||||
}
|
||||
|
||||
function buildToolTitle(binding: AgentToolBinding) {
|
||||
function findMatchedToolOption(
|
||||
binding: AgentToolBinding,
|
||||
options: AgentOption[],
|
||||
) {
|
||||
const targetId = String(binding.targetId || '');
|
||||
if (!targetId) return undefined;
|
||||
return options.find((item) => {
|
||||
const raw = item.raw || {};
|
||||
return (
|
||||
String(item.value) === targetId ||
|
||||
String(raw.id || '') === targetId ||
|
||||
String(raw.mcpId || '') === targetId
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function buildToolTitle(binding: AgentToolBinding, options: AgentOption[] = []) {
|
||||
const matchedOption = findMatchedToolOption(binding, options);
|
||||
return firstText(
|
||||
binding.resourceSummary?.title,
|
||||
binding.resourceSummary?.name,
|
||||
binding.resourceSummary?.label,
|
||||
binding.resourceSummary?.displayName,
|
||||
binding.resourceSummary?.mcpTitle,
|
||||
binding.resourceSnapshot?.title,
|
||||
binding.resourceSnapshot?.name,
|
||||
binding.resourceSnapshot?.label,
|
||||
binding.resourceSnapshot?.displayName,
|
||||
binding.resourceSnapshot?.mcpTitle,
|
||||
matchedOption?.label,
|
||||
matchedOption?.raw?.title,
|
||||
matchedOption?.raw?.name,
|
||||
matchedOption?.raw?.label,
|
||||
matchedOption?.raw?.displayName,
|
||||
matchedOption?.raw?.mcpTitle,
|
||||
binding.toolName,
|
||||
);
|
||||
}
|
||||
|
||||
function buildToolDetail(binding: AgentToolBinding, fallback: string) {
|
||||
function buildToolDetail(
|
||||
binding: AgentToolBinding,
|
||||
fallback: string,
|
||||
options: AgentOption[] = [],
|
||||
) {
|
||||
if (String(binding.toolType || '').toUpperCase() === 'MCP') {
|
||||
const matchedOption = findMatchedToolOption(binding, options);
|
||||
const resourceName = buildToolTitle(binding, options);
|
||||
const tools =
|
||||
binding.resourceSummary?.tools ||
|
||||
binding.resourceSnapshot?.tools ||
|
||||
matchedOption?.raw?.tools ||
|
||||
[];
|
||||
const toolCount = Array.isArray(tools) ? tools.length : 0;
|
||||
if (resourceName && toolCount > 0) {
|
||||
return `${resourceName} · ${toolCount} 个工具`;
|
||||
}
|
||||
return resourceName || fallback;
|
||||
}
|
||||
const toolName = firstText(binding.toolName);
|
||||
const resourceName = buildToolTitle(binding);
|
||||
const resourceName = buildToolTitle(binding, options);
|
||||
if (toolName && resourceName && toolName !== resourceName) {
|
||||
return `${resourceName} / ${toolName}`;
|
||||
}
|
||||
@@ -157,6 +204,11 @@ export function useAgentStudioModel(
|
||||
layout?: AgentStudioLayoutSnapshot,
|
||||
canvasSize?: () => AgentStudioCanvasSize | undefined,
|
||||
knowledgeOptions?: () => AgentOption[],
|
||||
toolOptions?: () => {
|
||||
mcp?: AgentOption[];
|
||||
plugin?: AgentOption[];
|
||||
workflow?: AgentOption[];
|
||||
},
|
||||
) {
|
||||
return computed(() => {
|
||||
const positionOf = (nodeId: string, fallback: { x: number; y: number }) =>
|
||||
@@ -214,10 +266,20 @@ export function useAgentStudioModel(
|
||||
});
|
||||
const toolNodes = state.toolBindings.map((binding, index) => {
|
||||
const nodeId = `tool:${binding.localId}`;
|
||||
const isWorkflow =
|
||||
String(binding.toolType || '').toUpperCase() === 'WORKFLOW';
|
||||
const fallback = isWorkflow ? '待选择工作流' : '待选择插件工具';
|
||||
const detail = buildToolDetail(binding, fallback);
|
||||
const toolType = String(binding.toolType || '').toUpperCase();
|
||||
const isWorkflow = toolType === 'WORKFLOW';
|
||||
const isMcp = toolType === 'MCP';
|
||||
const matchedOptions = isWorkflow
|
||||
? toolOptions?.().workflow || []
|
||||
: isMcp
|
||||
? toolOptions?.().mcp || []
|
||||
: toolOptions?.().plugin || [];
|
||||
const fallback = isWorkflow
|
||||
? '待选择工作流'
|
||||
: isMcp
|
||||
? '待选择 MCP'
|
||||
: '待选择插件工具';
|
||||
const detail = buildToolDetail(binding, fallback, matchedOptions);
|
||||
const position = resolveCapabilityNodePosition({
|
||||
canvasSize: size,
|
||||
fallbackIndex: state.knowledgeBindings.length + index,
|
||||
@@ -233,14 +295,20 @@ export function useAgentStudioModel(
|
||||
width: CAPABILITY_NODE_WIDTH,
|
||||
height: CAPABILITY_NODE_HEIGHT,
|
||||
data: {
|
||||
badge: isWorkflow ? '工作流' : '插件',
|
||||
badge: isWorkflow ? '工作流' : isMcp ? 'MCP' : '插件',
|
||||
detail,
|
||||
iconKey: isWorkflow ? 'workflow' : 'plugin',
|
||||
iconKey: isWorkflow ? 'workflow' : isMcp ? 'mcp' : 'plugin',
|
||||
id: nodeId,
|
||||
kind: isWorkflow ? 'workflow' : 'plugin',
|
||||
kind: isWorkflow ? 'workflow' : isMcp ? 'mcp' : 'plugin',
|
||||
selected: selectedNodeId() === nodeId,
|
||||
title:
|
||||
detail === fallback ? (isWorkflow ? '工作流' : '插件') : detail,
|
||||
detail === fallback
|
||||
? isWorkflow
|
||||
? '工作流'
|
||||
: isMcp
|
||||
? 'MCP'
|
||||
: '插件'
|
||||
: detail,
|
||||
} satisfies AgentStudioNodeData,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user