fix: 完成系统向智能体数据链路切换
- 切换工作台、聊天历史、资源候选与公共调用到 Agent - 加固资源绑定、删除保护及发布运行并发控制 - 隔离旧 Bot 专属服务和组件并保留兼容入口
This commit is contained in:
@@ -78,7 +78,7 @@ export interface AgentChatCapabilityPayload {
|
||||
}
|
||||
|
||||
export function getPublishedAgents() {
|
||||
return api.get<RequestResult<AgentInfo[]>>('/api/v1/agent/list', {
|
||||
return api.get<RequestResult<AgentInfo[]>>('/api/v1/agent/options', {
|
||||
params: { publishedOnly: true },
|
||||
});
|
||||
}
|
||||
@@ -95,10 +95,7 @@ export function getAgentSession(sessionId: number | string) {
|
||||
|
||||
export function getPublishedKnowledges() {
|
||||
return api.get<RequestResult<AgentChatKnowledgeView[]>>(
|
||||
'/api/v1/documentCollection/list',
|
||||
{
|
||||
params: { publishedOnly: true },
|
||||
},
|
||||
'/api/v1/agent/knowledgeOptions',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,8 @@ import {
|
||||
|
||||
import {
|
||||
getAgentDetail,
|
||||
getAgentModels,
|
||||
getMcpPage,
|
||||
getMcpTools,
|
||||
getPublishedKnowledgeList,
|
||||
getAgentMcpToolOptions,
|
||||
getAgentResourceOptions,
|
||||
saveAgent,
|
||||
submitAgentOfflineApproval,
|
||||
submitAgentPublishApproval,
|
||||
@@ -76,7 +74,7 @@ const workflows = ref<AgentOption[]>([]);
|
||||
const pluginTools = ref<AgentOption[]>([]);
|
||||
const mcps = ref<AgentOption[]>([]);
|
||||
const fetchMcpToolResource = createMcpToolLoader(async (id) => {
|
||||
const res = await getMcpTools(id);
|
||||
const res = await getAgentMcpToolOptions(id);
|
||||
return res.errorCode === 0 ? res.data : undefined;
|
||||
});
|
||||
|
||||
@@ -128,7 +126,6 @@ const offlineDisabled = computed(() => {
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
void loadDeferredOptions();
|
||||
try {
|
||||
await Promise.all([loadCriticalOptions(), loadAgent()]);
|
||||
} finally {
|
||||
@@ -213,11 +210,11 @@ function syncNavTitle(title: string, options: { force?: boolean } = {}) {
|
||||
}
|
||||
|
||||
async function loadCriticalOptions() {
|
||||
const [categoryResult, modelResult] = await Promise.allSettled([
|
||||
const [categoryResult, resourceResult] = await Promise.allSettled([
|
||||
api.get('/api/v1/agentCategory/visibleList', {
|
||||
params: { sortKey: 'sortNo', sortType: 'asc' },
|
||||
}),
|
||||
getAgentModels(),
|
||||
getAgentResourceOptions(),
|
||||
]);
|
||||
|
||||
if (categoryResult.status === 'fulfilled') {
|
||||
@@ -227,71 +224,33 @@ async function loadCriticalOptions() {
|
||||
raw: item,
|
||||
}));
|
||||
}
|
||||
if (modelResult.status === 'fulfilled') {
|
||||
models.value = (modelResult.value.data || []).map((item: any) => ({
|
||||
if (resourceResult.status === 'fulfilled') {
|
||||
const resources = resourceResult.value.data;
|
||||
if (resourceResult.value.errorCode !== 0 || !resources) {
|
||||
return;
|
||||
}
|
||||
models.value = (resources.models || []).map((item: any) => ({
|
||||
label: item.title || item.name,
|
||||
value: String(item.id),
|
||||
raw: item,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDeferredOptions() {
|
||||
const [knowledgeResult, workflowResult, pluginResult, mcpResult] =
|
||||
await Promise.allSettled([
|
||||
getPublishedKnowledgeList(),
|
||||
api.get('/api/v1/workflow/page', {
|
||||
params: { pageNumber: 1, pageSize: 200 },
|
||||
}),
|
||||
api.get('/api/v1/plugin/pageByCategory', {
|
||||
params: { pageNumber: 1, pageSize: 200, category: 0 },
|
||||
}),
|
||||
getMcpPage(),
|
||||
]);
|
||||
|
||||
if (knowledgeResult.status === 'fulfilled') {
|
||||
knowledges.value = (knowledgeResult.value.data || []).map((item: any) => ({
|
||||
knowledges.value = (resources.knowledges || []).map((item: any) => ({
|
||||
label: item.title || item.name,
|
||||
value: String(item.id),
|
||||
raw: item,
|
||||
}));
|
||||
}
|
||||
if (workflowResult.status === 'fulfilled') {
|
||||
workflows.value = (
|
||||
(workflowResult.value.data?.records ||
|
||||
workflowResult.value.data ||
|
||||
[]) as any[]
|
||||
).map((item) => ({
|
||||
workflows.value = (resources.workflows || []).map((item: any) => ({
|
||||
label: item.title || item.name,
|
||||
value: String(item.id),
|
||||
raw: item,
|
||||
}));
|
||||
pluginTools.value = (resources.pluginTools || []).map((item: any) => ({
|
||||
label: item.name || item.title,
|
||||
value: String(item.id),
|
||||
raw: item,
|
||||
}));
|
||||
mcps.value = mapMcpOptions(resources.mcps || []);
|
||||
}
|
||||
if (pluginResult.status === 'fulfilled') {
|
||||
pluginTools.value = flattenPluginTools(
|
||||
pluginResult.value.data?.records || pluginResult.value.data || [],
|
||||
);
|
||||
}
|
||||
if (mcpResult.status === 'fulfilled') {
|
||||
mcps.value = mapMcpOptions(
|
||||
mcpResult.value.data?.records || mcpResult.value.data || [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenPluginTools(list: any[]): AgentOption[] {
|
||||
const result: AgentOption[] = [];
|
||||
list.forEach((plugin) => {
|
||||
const tools = Array.isArray(plugin.tools) ? plugin.tools : [];
|
||||
tools.forEach((tool: any) => {
|
||||
result.push({
|
||||
label: tool.name || tool.title,
|
||||
value: String(tool.id),
|
||||
raw: { ...tool, pluginName: plugin.name || plugin.title },
|
||||
});
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function mapMcpOptions(list: any[]): AgentOption[] {
|
||||
@@ -325,8 +284,7 @@ async function loadMcpToolsForOption(id: number | string) {
|
||||
const currentOption = mcps.value.find((item) => String(item.value) === key);
|
||||
const mergedResource = {
|
||||
...currentOption?.raw,
|
||||
...resource,
|
||||
tools: Array.isArray(resource.tools) ? resource.tools : [],
|
||||
tools: Array.isArray(resource) ? resource : [],
|
||||
};
|
||||
if (currentOption) {
|
||||
mcps.value = mcps.value.map((item) =>
|
||||
@@ -334,7 +292,7 @@ async function loadMcpToolsForOption(id: number | string) {
|
||||
? {
|
||||
...item,
|
||||
label:
|
||||
resource.title || resource.name || currentOption.label || 'MCP',
|
||||
currentOption.label || 'MCP',
|
||||
raw: mergedResource,
|
||||
}
|
||||
: item,
|
||||
|
||||
@@ -12,7 +12,7 @@ import {Delete, Edit, Plus, Promotion} from '@element-plus/icons-vue';
|
||||
import {ElMessage, ElMessageBox, ElTag} from 'element-plus';
|
||||
import {tryit} from 'radash';
|
||||
|
||||
import defaultAvatar from '#/assets/ai/bot/defaultBotAvatar.png';
|
||||
import defaultAgentAvatar from '#/assets/defaultUserAvatar.png';
|
||||
import HeaderSearch from '#/components/headerSearch/HeaderSearch.vue';
|
||||
import PageData from '#/components/page/PageData.vue';
|
||||
import PageSide from '#/components/page/PageSide.vue';
|
||||
@@ -262,7 +262,7 @@ async function handleDeleteAction(row: AgentInfo) {
|
||||
<CardList
|
||||
title-field="name"
|
||||
icon-field="avatar"
|
||||
:default-icon="defaultAvatar"
|
||||
:default-icon="defaultAgentAvatar"
|
||||
:data="pageList"
|
||||
:primary-action="primaryAction"
|
||||
:actions="actions"
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type {AgentInfo, AgentKnowledgeBinding, AgentToolBinding,} from './types';
|
||||
import type {
|
||||
AgentInfo,
|
||||
AgentKnowledgeBinding,
|
||||
AgentToolBinding,
|
||||
} from './types';
|
||||
|
||||
import {api} from '#/api/request';
|
||||
import { api } from '#/api/request';
|
||||
|
||||
export interface RequestResult<T = any> {
|
||||
data: T;
|
||||
@@ -22,10 +26,6 @@ export function updateAgent(agent: AgentInfo) {
|
||||
return api.post<RequestResult<AgentInfo>>('/api/v1/agent/update', agent);
|
||||
}
|
||||
|
||||
export function removeAgent(id: number | string) {
|
||||
return api.post<RequestResult>('/api/v1/agent/remove', { id });
|
||||
}
|
||||
|
||||
export function updateAgentToolBindings(
|
||||
agentId: number | string,
|
||||
bindings: AgentToolBinding[],
|
||||
@@ -98,24 +98,22 @@ export function getAgentCategories() {
|
||||
});
|
||||
}
|
||||
|
||||
export function getAgentModels() {
|
||||
return api.get<RequestResult<any[]>>('/api/v1/model/list', {
|
||||
params: { modelType: 'chatModel', added: true },
|
||||
});
|
||||
export interface AgentResourceOptions {
|
||||
knowledges: any[];
|
||||
mcps: any[];
|
||||
models: any[];
|
||||
pluginTools: any[];
|
||||
workflows: any[];
|
||||
}
|
||||
|
||||
export function getPublishedKnowledgeList() {
|
||||
return api.get<RequestResult<any[]>>('/api/v1/documentCollection/list', {
|
||||
params: { publishedOnly: true },
|
||||
});
|
||||
export function getAgentResourceOptions() {
|
||||
return api.get<RequestResult<AgentResourceOptions>>(
|
||||
'/api/v1/agent/resourceOptions',
|
||||
);
|
||||
}
|
||||
|
||||
export function getMcpPage() {
|
||||
return api.get<RequestResult<any>>('/api/v1/mcp/page', {
|
||||
params: { pageNumber: 1, pageSize: 200, status: 1 },
|
||||
export function getAgentMcpToolOptions(id: number | string) {
|
||||
return api.get<RequestResult<any[]>>('/api/v1/agent/mcpToolOptions', {
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
export function getMcpTools(id: number | string) {
|
||||
return api.post<RequestResult<any>>('/api/v1/mcp/getMcpTools', { id });
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import pageSource from './index.vue?raw';
|
||||
|
||||
describe('管理端智能体聊天历史契约', () => {
|
||||
it('使用智能体候选接口并保留 assistantId 查询参数', () => {
|
||||
expect(pageSource).toContain("'/api/v1/agent/list'");
|
||||
expect(pageSource).toContain("'/api/v1/agent/options'");
|
||||
expect(pageSource).not.toContain('/api/v1/bot/list');
|
||||
expect(pageSource).toContain('label: item.name');
|
||||
expect(pageSource).toContain('assistantId: query.value.assistantId');
|
||||
|
||||
@@ -98,7 +98,7 @@ onMounted(async () => {
|
||||
|
||||
async function fetchAgents() {
|
||||
agentLoading.value = true;
|
||||
const [error, res] = await tryit(api.get)('/api/v1/agent/list');
|
||||
const [error, res] = await tryit(api.get)('/api/v1/agent/options');
|
||||
agentLoading.value = false;
|
||||
if (error || res?.errorCode !== 0) {
|
||||
agentOptions.value = [];
|
||||
|
||||
@@ -360,11 +360,11 @@ const submitOfflineAction = async (item: any) => {
|
||||
}
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
impactRes.data?.hasBotBindings
|
||||
impactRes.data?.hasAgentBindings
|
||||
? buildOfflineImpactMessage(
|
||||
$t('documentCollection.offlineImpactBoundBotsIntro'),
|
||||
impactRes.data.botBindings,
|
||||
$t('documentCollection.offlineImpactBoundBotsFooter'),
|
||||
$t('documentCollection.offlineImpactBoundAgentsIntro'),
|
||||
impactRes.data.agentBindings,
|
||||
$t('documentCollection.offlineImpactBoundAgentsFooter'),
|
||||
)
|
||||
: $t('documentCollection.submitOfflineApprovalConfirm'),
|
||||
$t('message.noticeTitle'),
|
||||
|
||||
@@ -7,10 +7,10 @@ export interface OfflineImpactBinding {
|
||||
|
||||
export interface OfflineImpactCheck {
|
||||
canProceed: boolean;
|
||||
hasBotBindings: boolean;
|
||||
hasAgentBindings: boolean;
|
||||
hasPluginBindings: boolean;
|
||||
hasWorkflowUsages: boolean;
|
||||
botBindings: OfflineImpactBinding[];
|
||||
agentBindings: OfflineImpactBinding[];
|
||||
pluginBindings: OfflineImpactBinding[];
|
||||
workflowUsages: OfflineImpactBinding[];
|
||||
message?: string;
|
||||
@@ -33,7 +33,13 @@ export function buildOfflineImpactMessage(
|
||||
h('p', intro),
|
||||
h(
|
||||
'ul',
|
||||
items.map((item) => h('li', { key: String(item.id || item.title || '') }, resolveTitle(item))),
|
||||
items.map((item) =>
|
||||
h(
|
||||
'li',
|
||||
{ key: String(item.id || item.title || '') },
|
||||
resolveTitle(item),
|
||||
),
|
||||
),
|
||||
),
|
||||
footer ? h('p', footer) : null,
|
||||
]);
|
||||
|
||||
@@ -797,15 +797,15 @@ async function submitOfflineAction(row: any) {
|
||||
}
|
||||
try {
|
||||
const sections = [];
|
||||
let offlineImpactFooter = $t('aiWorkflow.offlineImpactBoundBotsFooter');
|
||||
if (impactRes.data?.hasBotBindings) {
|
||||
let offlineImpactFooter = $t('aiWorkflow.offlineImpactBoundAgentsFooter');
|
||||
if (impactRes.data?.hasAgentBindings) {
|
||||
sections.push(
|
||||
buildOfflineImpactMessage(
|
||||
$t('aiWorkflow.offlineImpactBoundBotsIntro'),
|
||||
impactRes.data.botBindings,
|
||||
$t('aiWorkflow.offlineImpactBoundAgentsIntro'),
|
||||
impactRes.data.agentBindings,
|
||||
impactRes.data?.hasPluginBindings
|
||||
? undefined
|
||||
: $t('aiWorkflow.offlineImpactBoundBotsFooter'),
|
||||
: $t('aiWorkflow.offlineImpactBoundAgentsFooter'),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -814,13 +814,13 @@ async function submitOfflineAction(row: any) {
|
||||
buildOfflineImpactMessage(
|
||||
$t('aiWorkflow.offlineImpactBoundPluginsIntro'),
|
||||
impactRes.data.pluginBindings,
|
||||
impactRes.data?.hasBotBindings
|
||||
impactRes.data?.hasAgentBindings
|
||||
? undefined
|
||||
: $t('aiWorkflow.offlineImpactBoundPluginsFooter'),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (impactRes.data?.hasBotBindings && impactRes.data?.hasPluginBindings) {
|
||||
if (impactRes.data?.hasAgentBindings && impactRes.data?.hasPluginBindings) {
|
||||
offlineImpactFooter = $t('aiWorkflow.offlineImpactBoundMixedFooter');
|
||||
} else if (impactRes.data?.hasPluginBindings) {
|
||||
offlineImpactFooter = $t('aiWorkflow.offlineImpactBoundPluginsFooter');
|
||||
|
||||
Reference in New Issue
Block a user