mirror of
https://github.com/labring/FastGPT.git
synced 2026-04-26 02:07:28 +08:00
Agent skill dev (#6668)
* chore: Rename service & container names for consistency in Docker configs (#6710) * chore: Rename container names for consistency in Docker configs * chore: Rename service names for consistency in Docker configs chore: Update OpenSandbox versions and image repositories (#6709) * chore: Update OpenSandbox versions and image repositories * yml version * images * init yml * port --------- Co-authored-by: archer <545436317@qq.com> refactor(chat): optimize sandbox status logic and decouple UI/Status hooks (#6713) * refactor(chat): optimize sandbox status logic and decouple UI/Status hooks * fix: useRef, rename onClose to afterClose Update .env.template (#6720) aiproxy默认的请求地址改成http协议 feat: comprehensive agent skill management and sandbox infrastructure optimization - Skill System: Implemented a full skill management module including CRUD operations, folder organization, AI-driven skill generation, and versioning (switch/update). - Sandbox Infrastructure: Introduced 'volume-manager' for PVC and Docker volume lifecycle management, replacing the MinIO sync-agent for better data persistence. - Workflow Integration: Enhanced the Agent node to support skill selection and configuration, including new UI components and data normalization. - Permission Management: Added granular permission controls for skills, supporting collaborators, owner transfers, and permission inheritance. - UI/UX: Added a dedicated Skill dashboard, sandbox debug interface (terminal, logs, and iframe proxy), and comprehensive i18n support. - Maintenance: Migrated Docker services to named volumes, optimized sandbox instance limits, and improved error handling for sandbox providers. Co-authored-by: chanzhi82020 <chenzhi@sangfor.com.cn> Co-authored-by: lavine77 Signed-off-by: Jon <ljp@sangfor.com.cn> feat: hide skill prettier * perf: hide skill code * fix: ts * lock * perf: tool code * fix: ts * lock * fix: test * fix: openapi * lock * fix: test * null model --------- Co-authored-by: archer <545436317@qq.com>
This commit is contained in:
@@ -95,6 +95,7 @@ export const iconPaths = {
|
||||
'common/selectLight': () => import('./icons/common/selectLight.svg'),
|
||||
'common/setting': () => import('./icons/common/setting.svg'),
|
||||
'common/settingLight': () => import('./icons/common/settingLight.svg'),
|
||||
'common/skill': () => import('./icons/common/skill.svg'),
|
||||
'common/solidChevronDown': () => import('./icons/common/solidChevronDown.svg'),
|
||||
'common/solidChevronUp': () => import('./icons/common/solidChevronUp.svg'),
|
||||
'common/templateMarket': () => import('./icons/common/templateMarket.svg'),
|
||||
@@ -103,6 +104,8 @@ export const iconPaths = {
|
||||
'common/toolkit': () => import('./icons/common/toolkit.svg'),
|
||||
'common/trash': () => import('./icons/common/trash.svg'),
|
||||
'common/uploadFileFill': () => import('./icons/common/uploadFileFill.svg'),
|
||||
'common/upperRight': () => import('./icons/common/upperRight.svg'),
|
||||
'common/user': () => import('./icons/common/user.svg'),
|
||||
'common/userInfo': () => import('./icons/common/userInfo.svg'),
|
||||
'common/variable': () => import('./icons/common/variable.svg'),
|
||||
'common/viewLight': () => import('./icons/common/viewLight.svg'),
|
||||
@@ -236,6 +239,9 @@ export const iconPaths = {
|
||||
'core/modules/basicNode': () => import('./icons/core/modules/basicNode.svg'),
|
||||
'core/modules/fitView': () => import('./icons/core/modules/fitView.svg'),
|
||||
'core/modules/variable': () => import('./icons/core/modules/variable.svg'),
|
||||
'core/modules/welcomeText': () => import('./icons/core/modules/welcomeText.svg'),
|
||||
'core/skill/default': () => import('./icons/core/skill/default.svg'),
|
||||
'core/skill/help': () => import('./icons/core/skill/help.svg'),
|
||||
'core/workflow/closeEdge': () => import('./icons/core/workflow/closeEdge.svg'),
|
||||
'core/workflow/debug': () => import('./icons/core/workflow/debug.svg'),
|
||||
'core/workflow/debugBlue': () => import('./icons/core/workflow/debugBlue.svg'),
|
||||
@@ -282,6 +288,11 @@ export const iconPaths = {
|
||||
'core/workflow/runSkip': () => import('./icons/core/workflow/runSkip.svg'),
|
||||
'core/workflow/runSuccess': () => import('./icons/core/workflow/runSuccess.svg'),
|
||||
'core/workflow/running': () => import('./icons/core/workflow/running.svg'),
|
||||
'core/workflow/template/BI': () => import('./icons/core/workflow/template/BI.svg'),
|
||||
'core/workflow/template/FileRead': () => import('./icons/core/workflow/template/FileRead.svg'),
|
||||
'core/workflow/template/agent': () => import('./icons/core/workflow/template/agent.svg'),
|
||||
'core/workflow/template/agentLinear': () =>
|
||||
import('./icons/core/workflow/template/agentLinear.tsx'),
|
||||
'core/workflow/template/aiChat': () => import('./icons/core/workflow/template/aiChat.svg'),
|
||||
'core/workflow/template/aiChatLinear': () =>
|
||||
import('./icons/core/workflow/template/aiChatLinear.tsx'),
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.2 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.1 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 17 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.9 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 24 24"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_1780_06419" gradientTransform="translate(0 -1.8666579723358154) rotate(56.4373879668184) scale(16.64101115449701 16.64101115449701)"><stop offset="32.69553184509277%" stop-color="#FFFFFF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#FFFFFF" stop-opacity="0"/></radialGradient><clipPath id="master_svg1_1780_14500"><rect x="0" y="0" width="24" height="24" rx="6"/></clipPath></defs><g clip-path="url(#master_svg1_1780_14500)"><rect x="0" y="0" width="24" height="24" rx="6" fill="#14A846" fill-opacity="1"/><rect x="0" y="0" width="24" height="24" rx="6" fill="url(#master_svg0_1780_06419)" fill-opacity="1"/><g><path d="M17.99735626068115,5.78602L17.158356260681153,4L16.319356260681154,5.78602L14.533356260681153,6.625L16.319356260681154,7.463979999999999L17.158356260681153,9.25L17.99735626068115,7.463979999999999L19.783356260681153,6.625L17.99735626068115,5.78602ZM12.899866260681152,10.23951C12.929606260681151,10.30282,12.980536260681152,10.35375,13.043846260681152,10.38349L15.519356260681151,11.54637L15.639256260681153,11.60266L16.705356260681153,12.10347C16.810556260681153,12.15291,16.877756260681153,12.25872,16.877756260681153,12.375C16.877756260681153,12.49128,16.810556260681153,12.59709,16.705356260681153,12.64653L15.639256260681153,13.14734L15.519356260681151,13.20363L13.043846260681152,14.3665C12.980536260681152,14.3963,12.929606260681151,14.4472,12.899866260681152,14.5105L11.736986260681153,16.986L11.680696260681152,17.1059L11.179896260681152,18.172C11.130446260681152,18.2772,11.024636260681152,18.3444,10.908356260681153,18.3444C10.792076260681153,18.3444,10.686266260681151,18.2772,10.636826260681152,18.172L10.136016260681153,17.1059L10.079726260681152,16.986L8.916846260681153,14.5105C8.887106260681152,14.4472,8.836176260681153,14.3963,8.772866260681152,14.3665L6.297336260681153,13.20363L6.177496260681153,13.14734L5.111394260681152,12.64653C5.0061456606811525,12.59709,4.938947478931152,12.49128,4.938947478931152,12.375C4.938947527431153,12.25872,5.0061456606811525,12.15291,5.111394260681152,12.10347L6.177496260681153,11.60266L6.297336260681153,11.54637L8.772866260681152,10.38349C8.836176260681153,10.35375,8.887106260681152,10.30282,8.916846260681153,10.23951L10.079726260681152,7.76398L10.136016260681153,7.64414L10.636826260681152,6.57804C10.686266260681151,6.47279,10.792076260681153,6.40559,10.908356260681153,6.40559C11.024636260681152,6.40559,11.130446260681152,6.47279,11.179896260681152,6.57804L11.680696260681152,7.64414L11.736986260681153,7.76398L12.899866260681152,10.23951ZM12.406086260681153,11.74116L13.755406260681152,12.375L12.406086260681153,13.00885Q11.818306260681151,13.28495,11.542196260681152,13.87274L10.908356260681153,15.2221L10.274516260681153,13.87273Q9.998406260681152,13.28495,9.410626260681152,13.00884L8.061306260681153,12.375L9.410626260681152,11.74116Q9.998406260681152,11.46505,10.274516260681153,10.877279999999999L10.908356260681153,9.52795L11.542206260681152,10.87727Q11.818306260681151,11.46505,12.406086260681153,11.74116Z" fill-rule="evenodd" fill="#FFFFFF" fill-opacity="1"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,39 @@
|
||||
import React, { useId } from 'react';
|
||||
|
||||
type AgentLinearProps = React.SVGProps<SVGSVGElement>;
|
||||
|
||||
const AgentLinear: React.FC<AgentLinearProps> = (props) => {
|
||||
const gradientId = useId();
|
||||
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none" {...props}>
|
||||
<path
|
||||
d="M36 11.57L34.32 8L32.64 11.57L29.07 13.25L32.64 14.93L34.32 18.5L36 14.93L39.57 13.25L36 11.57Z"
|
||||
stroke={`url(#${gradientId})`}
|
||||
strokeWidth="2"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M25.8 20.48C25.86 20.61 25.96 20.71 26.09 20.77L31.04 23.09L33.41 24.21C33.62 24.31 33.76 24.52 33.76 24.75C33.76 24.98 33.62 25.19 33.41 25.29L31.04 26.41L26.09 28.73C25.96 28.79 25.86 28.89 25.8 29.02L23.47 33.97L21.18 36.69C21.07 36.9 20.86 37.01 20.65 37.01C20.44 37.01 20.23 36.9 20.12 36.69L17.83 33.97L15.5 29.02C15.44 28.89 15.34 28.79 15.21 28.73L10.26 26.41L7.89 25.29C7.68 25.19 7.54 24.98 7.54 24.75C7.54 24.52 7.68 24.31 7.89 24.21L10.26 23.09L15.21 20.77C15.34 20.71 15.44 20.61 15.5 20.48L17.83 15.53L20.12 12.81C20.23 12.6 20.44 12.49 20.65 12.49C20.86 12.49 21.07 12.6 21.18 12.81L23.47 15.53L25.8 20.48Z"
|
||||
stroke={`url(#${gradientId})`}
|
||||
strokeWidth="2"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={gradientId}
|
||||
x1="22"
|
||||
y1="8"
|
||||
x2="22"
|
||||
y2="40"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#4ADE80" />
|
||||
<stop offset="1" stopColor="#14A846" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default AgentLinear;
|
||||
@@ -16,6 +16,7 @@ import MyDivider from '../MyDivider';
|
||||
import type { IconNameType } from '../Icon/type';
|
||||
import { useSystem } from '../../../hooks/useSystem';
|
||||
import Avatar from '../Avatar';
|
||||
import MyTooltip from '../MyTooltip';
|
||||
|
||||
export type MenuItemType = 'primary' | 'danger' | 'gray' | 'grayBg';
|
||||
export type MenuSizeType = 'sm' | 'md' | 'xs' | 'mini';
|
||||
@@ -30,6 +31,8 @@ export type MenuItemData = {
|
||||
description?: string;
|
||||
onClick?: () => any;
|
||||
menuItemStyles?: MenuItemProps;
|
||||
disabled?: boolean;
|
||||
disabledTip?: string;
|
||||
}>;
|
||||
};
|
||||
export type Props = {
|
||||
@@ -286,59 +289,74 @@ const MyMenu = ({
|
||||
<Box key={i}>
|
||||
{item.label && <Box fontSize={'sm'}>{item.label}</Box>}
|
||||
{i !== 0 && <MyDivider h={'1.5px'} {...sizeMapStyle[size].dividerStyle} />}
|
||||
{item.children.map((child, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
borderRadius={'sm'}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (child.onClick) {
|
||||
setIsOpen(false);
|
||||
child.onClick();
|
||||
}
|
||||
}}
|
||||
alignItems={'center'}
|
||||
fontSize={'sm'}
|
||||
color={child.isActive ? 'primary.700' : 'myGray.600'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
{...typeMapStyle[child.type || 'primary'].styles}
|
||||
{...sizeMapStyle[size].menuItemStyle}
|
||||
{...child.menuItemStyles}
|
||||
>
|
||||
{!!child.icon && (
|
||||
<Avatar
|
||||
src={child.icon as any}
|
||||
mr={2}
|
||||
{...sizeMapStyle[size].iconStyle}
|
||||
color={
|
||||
child.isActive
|
||||
? 'inherit'
|
||||
: typeMapStyle[child.type || 'primary'].iconColor
|
||||
{item.children.map((child, index) => {
|
||||
const menuItem = (
|
||||
<MenuItem
|
||||
key={index}
|
||||
borderRadius={'sm'}
|
||||
isDisabled={child.disabled}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (child.disabled) {
|
||||
return;
|
||||
}
|
||||
sx={{
|
||||
'[role="menuitem"]:hover &': {
|
||||
color: 'inherit'
|
||||
if (child.onClick) {
|
||||
setIsOpen(false);
|
||||
child.onClick();
|
||||
}
|
||||
}}
|
||||
alignItems={'center'}
|
||||
fontSize={'sm'}
|
||||
color={child.isActive ? 'primary.700' : 'myGray.600'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
{...typeMapStyle[child.type || 'primary'].styles}
|
||||
{...sizeMapStyle[size].menuItemStyle}
|
||||
{...child.menuItemStyles}
|
||||
>
|
||||
{!!child.icon && (
|
||||
<Avatar
|
||||
src={child.icon as any}
|
||||
mr={2}
|
||||
{...sizeMapStyle[size].iconStyle}
|
||||
color={
|
||||
child.isActive
|
||||
? 'inherit'
|
||||
: typeMapStyle[child.type || 'primary'].iconColor
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Box w={'100%'}>
|
||||
<Box
|
||||
w={'100%'}
|
||||
color={child.description ? 'myGray.900' : 'inherit'}
|
||||
pr={child.icon ? 4 : 0}
|
||||
{...sizeMapStyle[size].labelStyle}
|
||||
>
|
||||
{child.label}
|
||||
</Box>
|
||||
{child.description && (
|
||||
<Box color={'myGray.500'} fontSize={'mini'} w={'100%'}>
|
||||
{child.description}
|
||||
</Box>
|
||||
sx={{
|
||||
'[role="menuitem"]:hover &': {
|
||||
color: 'inherit'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</MenuItem>
|
||||
))}
|
||||
<Box w={'100%'}>
|
||||
<Box
|
||||
w={'100%'}
|
||||
color={child.description ? 'myGray.900' : 'inherit'}
|
||||
pr={child.icon ? 4 : 0}
|
||||
{...sizeMapStyle[size].labelStyle}
|
||||
>
|
||||
{child.label}
|
||||
</Box>
|
||||
{child.description && !child.disabled && (
|
||||
<Box color={'myGray.500'} fontSize={'mini'} w={'100%'}>
|
||||
{child.description}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</MenuItem>
|
||||
);
|
||||
|
||||
if (child.disabled && child.disabledTip) {
|
||||
return (
|
||||
<MyTooltip shouldWrapChildren={false} key={index} label={child.disabledTip}>
|
||||
{menuItem}
|
||||
</MyTooltip>
|
||||
);
|
||||
}
|
||||
return menuItem;
|
||||
})}
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { type Monaco } from '@monaco-editor/react';
|
||||
|
||||
type CompletionItemProvider = Parameters<Monaco['languages']['registerCompletionItemProvider']>[1];
|
||||
type ProvideCompletionItemsFn = CompletionItemProvider['provideCompletionItems'];
|
||||
|
||||
export type CompletionModel = Parameters<ProvideCompletionItemsFn>[0];
|
||||
export type CompletionPosition = Parameters<ProvideCompletionItemsFn>[1];
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Monaco } from '@monaco-editor/react';
|
||||
import { useCallback } from 'react';
|
||||
import { type CompletionModel, type CompletionPosition } from './type';
|
||||
|
||||
/**
|
||||
* Sandbox runtime type declarations.
|
||||
@@ -103,7 +104,7 @@ const useJSCompletion = () => {
|
||||
|
||||
monaco.languages.registerCompletionItemProvider('javascript', {
|
||||
triggerCharacters: ['.'],
|
||||
provideCompletionItems: (model, position) => {
|
||||
provideCompletionItems: (model: CompletionModel, position: CompletionPosition) => {
|
||||
const wordInfo = model.getWordUntilPosition(position);
|
||||
const currentWordPrefix = wordInfo.word;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Monaco } from '@monaco-editor/react';
|
||||
import { useCallback } from 'react';
|
||||
import { type CompletionModel, type CompletionPosition } from './type';
|
||||
|
||||
let monacoInstance: Monaco | null = null;
|
||||
|
||||
@@ -10,7 +11,7 @@ const usePythonCompletion = () => {
|
||||
|
||||
monaco.languages.registerCompletionItemProvider('python', {
|
||||
triggerCharacters: ['_'],
|
||||
provideCompletionItems: (model, position) => {
|
||||
provideCompletionItems: (model: CompletionModel, position: CompletionPosition) => {
|
||||
const wordInfo = model.getWordUntilPosition(position);
|
||||
const currentWordPrefix = wordInfo.word;
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Monaco } from '@monaco-editor/react';
|
||||
import { useCallback } from 'react';
|
||||
import { type CompletionModel, type CompletionPosition } from './type';
|
||||
|
||||
let monacoInstance: Monaco | null = null;
|
||||
|
||||
@@ -10,16 +11,8 @@ const useSystemHelperCompletion = () => {
|
||||
|
||||
const buildSuggestions = (
|
||||
monaco: Monaco,
|
||||
model: Parameters<
|
||||
Parameters<
|
||||
typeof monaco.languages.registerCompletionItemProvider
|
||||
>[1]['provideCompletionItems']
|
||||
>[0],
|
||||
position: Parameters<
|
||||
Parameters<
|
||||
typeof monaco.languages.registerCompletionItemProvider
|
||||
>[1]['provideCompletionItems']
|
||||
>[1],
|
||||
model: CompletionModel,
|
||||
position: CompletionPosition,
|
||||
memberSnippet: string
|
||||
) => {
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
@@ -76,7 +69,7 @@ const useSystemHelperCompletion = () => {
|
||||
for (const lang of ['javascript', 'typescript'] as const) {
|
||||
monaco.languages.registerCompletionItemProvider(lang, {
|
||||
triggerCharacters: ['.'],
|
||||
provideCompletionItems: (model, position) =>
|
||||
provideCompletionItems: (model: CompletionModel, position: CompletionPosition) =>
|
||||
buildSuggestions(monaco, model, position, jsSnippet)
|
||||
});
|
||||
}
|
||||
@@ -85,7 +78,7 @@ const useSystemHelperCompletion = () => {
|
||||
const pySnippet = 'httpRequest(${1:url}, method="${2:GET}", headers={}, timeout=${3:60})';
|
||||
monaco.languages.registerCompletionItemProvider('python', {
|
||||
triggerCharacters: ['.'],
|
||||
provideCompletionItems: (model, position) =>
|
||||
provideCompletionItems: (model: CompletionModel, position: CompletionPosition) =>
|
||||
buildSuggestions(monaco, model, position, pySnippet)
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -98,6 +98,16 @@ const NodeInputSelect = ({
|
||||
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.custom].icon,
|
||||
title: t('common:core.workflow.inputType.Manual input')
|
||||
},
|
||||
{
|
||||
type: FlowNodeInputTypeEnum.selectSkill,
|
||||
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.selectSkill].icon,
|
||||
title: t('common:core.workflow.inputType.Manual select')
|
||||
},
|
||||
{
|
||||
type: FlowNodeInputTypeEnum.selectTool,
|
||||
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.selectTool].icon,
|
||||
title: t('common:core.workflow.inputType.Manual select')
|
||||
},
|
||||
{
|
||||
type: FlowNodeInputTypeEnum.fileSelect,
|
||||
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.fileSelect].icon,
|
||||
|
||||
Reference in New Issue
Block a user