feat: 完善 Agent 标准交互与安全运行时

- 接入 AG-UI 运行投影、Turn 时间线和审批隔离

- 增加 Agent Skill 冻结绑定与运行时消费闭环

- 增加受控工作区、内置工具和私有 Artifact 生命周期
This commit is contained in:
2026-08-19 22:13:41 +08:00
parent 91d66e636d
commit 4e8640dcaf
241 changed files with 24382 additions and 2777 deletions

View File

@@ -142,6 +142,28 @@ function buildToolDetail(
return resourceName || toolName || fallback;
}
function resolveToolNodePresentation(toolType: string) {
if (toolType === 'WORKFLOW') {
return {
fallback: '待选择工作流',
kind: 'workflow' as const,
title: '工作流',
};
}
if (toolType === 'MCP') {
return {
fallback: '待选择 MCP',
kind: 'mcp' as const,
title: 'MCP',
};
}
return {
fallback: '待选择插件工具',
kind: 'plugin' as const,
title: '插件',
};
}
function toFlowPoint(
point: { x: number; y: number },
viewport: NonNullable<AgentStudioLayoutSnapshot['viewport']>,
@@ -296,19 +318,13 @@ export function useAgentStudioModel(
const toolNodes = state.toolBindings.map((binding, index) => {
const nodeId = `tool:${binding.localId}`;
const toolType = String(binding.toolType || '').toUpperCase();
const isWorkflow = toolType === 'WORKFLOW';
const isMcp = toolType === 'MCP';
const matchedOptions = isWorkflow
? toolOptionLookups.workflow
: isMcp
? toolOptionLookups.mcp
: toolOptionLookups.plugin;
const fallback = isWorkflow
? '待选择工作流'
: isMcp
? '待选择 MCP'
: '待选择插件工具';
const detail = buildToolDetail(binding, fallback, matchedOptions);
const presentation = resolveToolNodePresentation(toolType);
const matchedOptions = toolOptionLookups[presentation.kind];
const detail = buildToolDetail(
binding,
presentation.fallback,
matchedOptions,
);
const position = resolveCapabilityNodePosition({
canvasSize: size,
fallbackIndex: state.knowledgeBindings.length + index,
@@ -324,25 +340,54 @@ export function useAgentStudioModel(
width: CAPABILITY_NODE_WIDTH,
height: CAPABILITY_NODE_HEIGHT,
data: {
badge: isWorkflow ? '工作流' : isMcp ? 'MCP' : '插件',
badge: presentation.title,
detail,
iconKey: isWorkflow ? 'workflow' : isMcp ? 'mcp' : 'plugin',
iconKey: presentation.kind,
id: nodeId,
kind: isWorkflow ? 'workflow' : isMcp ? 'mcp' : 'plugin',
kind: presentation.kind,
selected: selectedNodeId() === nodeId,
title:
detail === fallback
? isWorkflow
? '工作流'
: isMcp
? 'MCP'
: '插件'
: detail,
title: detail === presentation.fallback ? presentation.title : detail,
} satisfies AgentStudioNodeData,
};
});
const capabilityNodes = [...knowledgeNodes, ...toolNodes];
const skillNodes: AgentStudioNodeView[] = [];
if (state.skillBindings.length > 0) {
const nodeId = 'skills';
const previewItems = state.skillBindings
.slice(0, 3)
.map((binding) =>
firstText(binding.resourceSummary?.displayName, '技能'),
);
const position = resolveCapabilityNodePosition({
canvasSize: size,
fallbackIndex:
state.knowledgeBindings.length + state.toolBindings.length,
layout,
nodeId,
occupiedPositions,
});
occupiedPositions.push(position);
skillNodes.push({
id: nodeId,
type: 'agentStudioCapability',
position,
width: 240,
height: 154,
data: {
detail: `${state.skillBindings.length} / 20`,
iconKey: 'skill',
id: nodeId,
kind: 'skill',
previewItems,
remainingCount: Math.max(0, state.skillBindings.length - 3),
selected: selectedNodeId() === nodeId,
title: '技能',
} satisfies AgentStudioNodeData,
});
}
const capabilityNodes = [...knowledgeNodes, ...toolNodes, ...skillNodes];
const edges: AgentStudioEdgeView[] = capabilityNodes.map((node) => ({
id: `edge:${node.id}`,