perf: 优化智能体与工作流幕布渲染性能

- 分阶段加载智能体配置并按需缓存 MCP 工具

- 合并画布状态更新与节点尺寸监听,启用大图可视区域渲染和静态连线

- 隔离 Tinyflow Store 实例并补充数据同步与回归测试
This commit is contained in:
2026-07-27 18:27:01 +08:00
parent dc7e46260b
commit aedefe6b5e
39 changed files with 1349 additions and 408 deletions

View File

@@ -31,13 +31,36 @@ function firstText(...values: unknown[]) {
return matched ? String(matched).trim() : '';
}
function createKnowledgeOptionLookup(options: AgentOption[]) {
const lookup = new Map<string, AgentOption>();
options.forEach((option) => {
const key = String(option.value);
if (!lookup.has(key)) {
lookup.set(key, option);
}
});
return lookup;
}
function createToolOptionLookup(options: AgentOption[]) {
const lookup = new Map<string, AgentOption>();
options.forEach((option) => {
const raw = option.raw || {};
[option.value, raw.id, raw.mcpId].forEach((value) => {
const key = String(value || '');
if (key && !lookup.has(key)) {
lookup.set(key, option);
}
});
});
return lookup;
}
function buildKnowledgeTitle(
binding: AgentKnowledgeBinding,
options: AgentOption[],
optionLookup: Map<string, AgentOption>,
) {
const matchedOption = options.find(
(item) => String(item.value) === String(binding.knowledgeId),
);
const matchedOption = optionLookup.get(String(binding.knowledgeId));
return firstText(
binding.resourceSummary?.title,
binding.resourceSummary?.name,
@@ -59,22 +82,18 @@ function buildKnowledgeTitle(
function findMatchedToolOption(
binding: AgentToolBinding,
options: AgentOption[],
optionLookup: Map<string, 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
);
});
return optionLookup.get(targetId);
}
function buildToolTitle(binding: AgentToolBinding, options: AgentOption[] = []) {
const matchedOption = findMatchedToolOption(binding, options);
function buildToolTitle(
binding: AgentToolBinding,
optionLookup: Map<string, AgentOption>,
matchedOption = findMatchedToolOption(binding, optionLookup),
) {
return firstText(
binding.resourceSummary?.title,
binding.resourceSummary?.name,
@@ -99,11 +118,11 @@ function buildToolTitle(binding: AgentToolBinding, options: AgentOption[] = [])
function buildToolDetail(
binding: AgentToolBinding,
fallback: string,
options: AgentOption[] = [],
optionLookup: Map<string, AgentOption>,
) {
if (String(binding.toolType || '').toUpperCase() === 'MCP') {
const matchedOption = findMatchedToolOption(binding, options);
const resourceName = buildToolTitle(binding, options);
const matchedOption = findMatchedToolOption(binding, optionLookup);
const resourceName = buildToolTitle(binding, optionLookup, matchedOption);
const tools =
binding.resourceSummary?.tools ||
binding.resourceSnapshot?.tools ||
@@ -116,7 +135,7 @@ function buildToolDetail(
return resourceName || fallback;
}
const toolName = firstText(binding.toolName);
const resourceName = buildToolTitle(binding, options);
const resourceName = buildToolTitle(binding, optionLookup);
if (toolName && resourceName && toolName !== resourceName) {
return `${resourceName} / ${toolName}`;
}
@@ -214,6 +233,16 @@ export function useAgentStudioModel(
const positionOf = (nodeId: string, fallback: { x: number; y: number }) =>
layout?.nodePositions?.[nodeId] || fallback;
const size = canvasSize?.();
const resolvedKnowledgeOptions = knowledgeOptions?.() || [];
const resolvedToolOptions = toolOptions?.() || {};
const knowledgeOptionLookup = createKnowledgeOptionLookup(
resolvedKnowledgeOptions,
);
const toolOptionLookups = {
mcp: createToolOptionLookup(resolvedToolOptions.mcp || []),
plugin: createToolOptionLookup(resolvedToolOptions.plugin || []),
workflow: createToolOptionLookup(resolvedToolOptions.workflow || []),
};
const occupiedPositions: Array<{ x: number; y: number }> = Object.values(
layout?.nodePositions || {},
);
@@ -238,7 +267,7 @@ export function useAgentStudioModel(
const knowledgeNodes = state.knowledgeBindings.map((binding, index) => {
const nodeId = `knowledge:${binding.localId}`;
const title = buildKnowledgeTitle(binding, knowledgeOptions?.() || []);
const title = buildKnowledgeTitle(binding, knowledgeOptionLookup);
const position = resolveCapabilityNodePosition({
canvasSize: size,
fallbackIndex: index,
@@ -270,10 +299,10 @@ export function useAgentStudioModel(
const isWorkflow = toolType === 'WORKFLOW';
const isMcp = toolType === 'MCP';
const matchedOptions = isWorkflow
? toolOptions?.().workflow || []
? toolOptionLookups.workflow
: isMcp
? toolOptions?.().mcp || []
: toolOptions?.().plugin || [];
? toolOptionLookups.mcp
: toolOptionLookups.plugin;
const fallback = isWorkflow
? '待选择工作流'
: isMcp