Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ pro/admin/worker/
/pro/llm_benchmark/content_benchmark/.env.*.local
/pro/llm_benchmark/content_benchmark/eval-runs/
/pro/llm_benchmark/content_benchmark/.cache/
.gstack/
3 changes: 3 additions & 0 deletions document/content/self-host/upgrading/4-15/4151.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@ The script only fills missing `appName` values. It does not overwrite existing v

1. Added global API Key tag management and an `appName` display snapshot for historical app-level API Keys, making older API keys compatible and easier to find when they were previously associated with apps.
2. Pre-extract the skill name and description when publishing a skill to help with generation.
3. The Plugin Marketplace now supports official/community source filters, and the system tool list supports status and tag filters.

## ⚙️ Improvements

1. Removed system field parameters when AgentV2 calls nested workflows.
2. System tools now support uninstall and reinstall. Uninstalling changes the tool status to Uninstalled and requires entering the tool name for confirmation. Uninstalled tools show only basic information and can be reinstalled.

## 🐛 Fixes

Expand All @@ -57,6 +59,7 @@ The script only fills missing `appName` values. It does not overwrite existing v
3. Fixed an issue where workflow tools did not initialize variables from the tool app's global variable configuration when running a sub-workflow, causing runtime variables such as default variables and system variables to be read incorrectly.
4. Fixed an issue where updates to global variables or outputs from nodes outside the container through **Variable Update** inside loop nodes and parallel execution nodes were not synchronized back to the main workflow by round or task completion. Successful rounds or tasks now write back their changes, while failed rounds or tasks do not commit their changes.
5. The component did not refresh immediately when retrying all Knowledge Base collections.
6. Fixed repeated shallow route updates in the embedded FastGPT Marketplace when filters did not change, which could keep the top progress bar loading.

## 🛠️ Code Improvements

Expand Down
3 changes: 3 additions & 0 deletions document/content/self-host/upgrading/4-15/4151.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ curl -X POST "{{host}}/api/admin/initv4151" \

1. 增加全局 API Key 标签管理,并为历史应用级 API Key 增加 `appName` 展示快照,便于兼容旧版 API 密钥并查找以前应用关联的密钥。
2. 发布技能时,预提取技能名称和描述,便于辅助生成。
3. 插件市场支持官方/社区来源筛选,系统工具列表的状态列和标签列支持筛选。

## ⚙️ 优化

1. AgentV2 调用嵌套工作流时候,去除系统字段参数。
2. 系统工具支持卸载和重新安装。卸载会将工具状态改为“已卸载”,需要输入工具名称确认;已卸载工具只展示基础信息,并可重新安装恢复。

## 🐛 修复

Expand All @@ -59,6 +61,7 @@ curl -X POST "{{host}}/api/admin/initv4151" \
3. 修复工作流工具运行子工作流时未按工具应用的全局变量配置初始化变量,导致默认变量、系统变量等运行态变量读取异常的问题。
4. 修复循环节点和并行执行节点中通过【变量更新】修改全局变量或容器外节点输出时,主流程未按轮次/任务结束同步更新的问题。成功轮次或成功任务会回写本轮变更,失败轮次或失败任务不提交本轮变更。
5. 重试全部知识库集合时,未立即刷新组件。
6. 修复 FastGPT 内嵌插件市场在筛选条件没有变化时重复更新浅路由,导致顶部进度条持续 loading 的问题。

## 🛠️ 代码优化

Expand Down
14 changes: 10 additions & 4 deletions packages/global/openapi/core/plugin/marketplace/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { PluginToolTagSchema } from '../../../../core/plugin/type';
import type { ToolListItemType } from '../../../../sdk/fastgpt-plugin';

export const MarketplaceOfficialSource = 'official';
export const MarketplaceCommunitySource = 'community';
export const MarketplacePkgSourceSchema = z.string().trim().min(1);
export const MarketplaceSourceFilterSchema = z.enum([
MarketplaceOfficialSource,
MarketplaceCommunitySource
]);
export type MarketplaceSourceFilterType = z.infer<typeof MarketplaceSourceFilterSchema>;

const formatToolDetailSchema = z.object({});
const formatToolSimpleSchema = z.object({});
Expand All @@ -15,6 +21,7 @@ export type MarketplaceToolListItemType = ToolListItemType & {
toolId: string;
downloadCount: number;
downloadUrl?: string;
source?: string;
};

export const MarketplaceToolDetailItemSchema = formatToolDetailSchema.extend({
Expand All @@ -27,7 +34,8 @@ export const MarketplaceToolDetailSchema = z.object({
// List
export const GetMarketplaceToolsBodySchema = PaginationSchema.extend({
searchKey: z.string().optional(),
tags: z.array(z.string()).nullish()
tags: z.array(z.string()).nullish(),
source: MarketplaceSourceFilterSchema.optional()
});
export type GetMarketplaceToolsBodyType = z.infer<typeof GetMarketplaceToolsBodySchema>;

Expand Down Expand Up @@ -98,9 +106,7 @@ export const DeleteMarketplacePkgResponseSchema = z.object({
description: '插件来源'
})
});
export type DeleteMarketplacePkgResponseType = z.infer<
typeof DeleteMarketplacePkgResponseSchema
>;
export type DeleteMarketplacePkgResponseType = z.infer<typeof DeleteMarketplacePkgResponseSchema>;

// Tags
export const GetMarketplaceToolTagsResponseSchema = z.array(PluginToolTagSchema);
Expand Down
160 changes: 140 additions & 20 deletions packages/web/components/core/plugin/tool/TagFilterBox.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import { Box, Flex } from '@chakra-ui/react';
import { Box, Flex, Menu, MenuButton, MenuItem, MenuList, Portal } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { parseI18nString } from '@fastgpt/global/common/i18n/utils';
import type { SystemPluginToolTagType } from '@fastgpt/global/core/plugin/type';
import React, { useMemo } from 'react';
import MyIcon from '../../../common/Icon';

export type MarketplaceSourceFilterValue = 'official' | 'community';

const ToolTagFilterBox = ({
tags,
selectedTagIds,
onTagSelect,
size = 'base'
selectedSource,
onSourceSelect,
size = 'base',
variant = 'default'
}: {
tags: SystemPluginToolTagType[];
selectedTagIds: string[];
onTagSelect: (tagIds: string[]) => void;
selectedSource?: MarketplaceSourceFilterValue;
onSourceSelect?: (source?: MarketplaceSourceFilterValue) => void;
size?: 'base' | 'sm';
variant?: 'default' | 'marketplace';
}) => {
const { t, i18n } = useTranslation();
const isMarketplaceVariant = variant === 'marketplace';
const sourceOptions = [
{ label: t('common:All'), value: undefined },
{ label: t('app:toolkit_official'), value: 'official' },
{ label: t('app:toolkit_community'), value: 'community' }
] as const;
const selectedSourceLabel =
sourceOptions.find((option) => option.value === selectedSource)?.label || t('common:All');

const toggleTag = (tagId: string) => {
if (selectedTagIds.includes(tagId)) {
Expand All @@ -27,11 +44,18 @@ const ToolTagFilterBox = ({

const tagBaseStyles = useMemo(() => {
const sizeStyles = {
base: {
px: 3,
py: 1.5,
fontSize: 'sm'
},
base: isMarketplaceVariant
? {
px: '13px',
h: '35px',
fontSize: '14px',
lineHeight: '21px'
}
: {
px: 3,
py: 1.5,
fontSize: 'sm'
},
sm: {
px: 2,
py: 1,
Expand All @@ -42,14 +66,20 @@ const ToolTagFilterBox = ({
return {
...sizeStyles[size],
fontWeight: 'medium',
color: 'myGray.700',
color: isMarketplaceVariant ? '#383F50' : 'myGray.700',
border: '1px solid',
borderColor: 'myGray.200',
borderColor: isMarketplaceVariant ? '#E8EBF0' : 'myGray.200',
whiteSpace: 'nowrap',
flexShrink: 0,
cursor: 'pointer'
cursor: 'pointer',
...(isMarketplaceVariant
? {
alignItems: 'center',
justifyContent: 'center'
}
: {})
};
}, [size]);
}, [isMarketplaceVariant, size]);

return (
<Flex
Expand Down Expand Up @@ -83,15 +113,98 @@ const ToolTagFilterBox = ({
}
}}
>
{isMarketplaceVariant ? (
<Menu placement="bottom-start" autoSelect={false} isLazy>
<MenuButton
as={Box}
{...tagBaseStyles}
display={'inline-block'}
w={'65px'}
rounded={'6px'}
bg={'white'}
position={'relative'}
_hover={{ bg: 'myGray.50' }}
_expanded={{ bg: 'myGray.50' }}
>
<Box
position={'absolute'}
left={'13px'}
top={'7px'}
h={'21px'}
lineHeight={'21px'}
whiteSpace={'nowrap'}
>
{selectedSourceLabel}
</Box>
<Box
position={'absolute'}
left={'45px'}
top={'10.5px'}
w={'7px'}
h={'14px'}
display={'flex'}
alignItems={'center'}
justifyContent={'center'}
overflow={'visible'}
>
<MyIcon
name={'core/chat/chevronSelector'}
w={'14px'}
h={'14px'}
color={'#667085'}
verticalAlign={'middle'}
/>
</Box>
</MenuButton>
<Portal>
<MenuList
minW={'92px'}
p={'6px'}
border={'1px solid'}
borderColor={'#E8EBF0'}
boxShadow={'3'}
zIndex={2000}
>
{sourceOptions.map((option) => {
const isSelected = option.value === selectedSource;

return (
<MenuItem
key={option.value ?? 'all'}
h={'32px'}
borderRadius={'6px'}
fontSize={'14px'}
fontWeight={'medium'}
color={isSelected ? 'primary.600' : '#383F50'}
bg={isSelected ? 'myGray.50' : 'white'}
_hover={{ bg: 'myGray.50' }}
onClick={() => onSourceSelect?.(option.value)}
>
<Box flex={1}>{option.label}</Box>
{isSelected && <MyIcon name={'common/check'} w={4} color={'primary.600'} />}
</MenuItem>
);
})}
</MenuList>
</Portal>
</Menu>
) : (
<Box
{...tagBaseStyles}
rounded={'sm'}
bg={selectedTagIds.length === 0 ? 'myGray.150' : 'transparent'}
onClick={() => onTagSelect([])}
>
{t('common:All')}
</Box>
)}
<Box
{...tagBaseStyles}
rounded={'sm'}
bg={selectedTagIds.length === 0 ? 'myGray.150' : 'transparent'}
onClick={() => onTagSelect([])}
>
{t('common:All')}
</Box>
<Box mx={2} h={'20px'} w={'1px'} bg={'myGray.200'} flexShrink={0} />
mx={2}
h={'20px'}
w={'1px'}
bg={isMarketplaceVariant ? '#E8EBF0' : 'myGray.200'}
flexShrink={0}
/>
<Box flex={1}>
<Flex gap={2} flexWrap="nowrap">
{tags.map((tag) => {
Expand All @@ -100,8 +213,15 @@ const ToolTagFilterBox = ({
<Box
key={tag.tagId}
{...tagBaseStyles}
display={isMarketplaceVariant ? 'inline-flex' : undefined}
rounded={'full'}
bg={isSelected ? 'myGray.150 !important' : 'transparent'}
bg={(() => {
if (isMarketplaceVariant) {
return isSelected ? 'myGray.50 !important' : 'white';
}
return isSelected ? 'myGray.150 !important' : 'transparent';
})()}
_hover={isMarketplaceVariant ? { bg: 'myGray.50' } : undefined}
onClick={() => toggleTag(tag.tagId)}
>
{t(parseI18nString(tag.tagName, i18n.language))}
Expand Down
Loading
Loading