mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-25 06:14:06 +00:00
feat: admin add custom plugin (#2582)
* feat: admin add custom plugin * refresh plugins * plugin input box ui * fix: run plugin varialbes error * perf: comment * fix: ts
This commit is contained in:
@@ -54,30 +54,31 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4810' \
|
||||
5. 新增 - 工作流本次编辑记录,取代自动保存
|
||||
6. 新增 - 工作流版本支持重命名
|
||||
7. 新增 - 应用调用迁移成单独节点,同时可以传递全局变量和用户的文件。
|
||||
8. 商业版新增 - 飞书机器人接入
|
||||
9. 商业版新增 - 公众号接入接入
|
||||
10. 商业版新增 - 自助开票申请
|
||||
11. 商业版新增 - SSO 定制
|
||||
12. 优化 - SSE 响应优化。
|
||||
13. 优化 - 无 SSL 证书情况下,优化复制。
|
||||
14. 优化 - 单选框打开后自动滚动到选中的位置。
|
||||
15. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
|
||||
16. 优化 - 节点选择,避免切换 tab 时候,path 加载报错。
|
||||
17. 优化 - 最新 React Markdown 组件,支持 Base64 图片。
|
||||
18. 优化 - 知识库列表 UI。
|
||||
19. 优化 - 知识库详情页 UI。
|
||||
20. 优化 - 支持无网络配置情况下运行。
|
||||
21. 优化 - 部分全局变量,增加数据类型约束。
|
||||
22. 修复 - 全局变量 key 可能重复。
|
||||
23. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。
|
||||
24. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。
|
||||
25. 修复 - 选择 Milvus 部署时,无法导出知识库。
|
||||
26. 修复 - 创建 APP 副本,无法复制系统配置。
|
||||
27. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
|
||||
28. 修复 - 内容提取的数据类型与输出数据类型未一致。
|
||||
29. 修复 - 工作流运行时间统计错误。
|
||||
30. 修复 - stream 模式下,工具调用有可能出现 undefined
|
||||
31. 修复 - 全局变量在 API 中无法持久化。
|
||||
32. 修复 - OpenAPI,detail=false模式下,不应该返回 tool 调用结果,仅返回文字。(可解决 cow 不适配问题)
|
||||
33. 修复 - 知识库标签重复加载。
|
||||
34. 修复 - Debug 模式下,循环调用边问题。
|
||||
8. 新增 - 插件增加使用说明配置。
|
||||
9. 商业版新增 - 飞书机器人接入
|
||||
10. 商业版新增 - 公众号接入接入
|
||||
11. 商业版新增 - 自助开票申请
|
||||
12. 商业版新增 - SSO 定制
|
||||
13. 优化 - SSE 响应优化。
|
||||
14. 优化 - 无 SSL 证书情况下,优化复制。
|
||||
15. 优化 - 单选框打开后自动滚动到选中的位置。
|
||||
16. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
|
||||
17. 优化 - 节点选择,避免切换 tab 时候,path 加载报错。
|
||||
18. 优化 - 最新 React Markdown 组件,支持 Base64 图片。
|
||||
19. 优化 - 知识库列表 UI。
|
||||
20. 优化 - 知识库详情页 UI。
|
||||
21. 优化 - 支持无网络配置情况下运行。
|
||||
22. 优化 - 部分全局变量,增加数据类型约束。
|
||||
23. 修复 - 全局变量 key 可能重复。
|
||||
24. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。
|
||||
25. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。
|
||||
26. 修复 - 选择 Milvus 部署时,无法导出知识库。
|
||||
27. 修复 - 创建 APP 副本,无法复制系统配置。
|
||||
28. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
|
||||
29. 修复 - 内容提取的数据类型与输出数据类型未一致。
|
||||
30. 修复 - 工作流运行时间统计错误。
|
||||
31. 修复 - stream 模式下,工具调用有可能出现 undefined
|
||||
32. 修复 - 全局变量在 API 中无法持久化。
|
||||
33. 修复 - OpenAPI,detail=false模式下,不应该返回 tool 调用结果,仅返回文字。(可解决 cow 不适配问题)
|
||||
34. 修复 - 知识库标签重复加载。
|
||||
35. 修复 - Debug 模式下,循环调用边问题。
|
||||
|
@@ -169,10 +169,10 @@ export type DispatchNodeResponseType = {
|
||||
export type DispatchNodeResultType<T> = {
|
||||
[DispatchNodeResponseKeyEnum.skipHandleId]?: string[]; // skip some edge handle id
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]?: DispatchNodeResponseType; // The node response detail
|
||||
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]?: ChatNodeUsageType[]; //
|
||||
[DispatchNodeResponseKeyEnum.childrenResponses]?: DispatchNodeResultType[];
|
||||
[DispatchNodeResponseKeyEnum.toolResponses]?: ToolRunResponseItemType;
|
||||
[DispatchNodeResponseKeyEnum.assistantResponses]?: ChatItemValueItemType[];
|
||||
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]?: ChatNodeUsageType[]; // Node total usage
|
||||
[DispatchNodeResponseKeyEnum.childrenResponses]?: DispatchNodeResultType[]; // Children node response
|
||||
[DispatchNodeResponseKeyEnum.toolResponses]?: ToolRunResponseItemType; // Tool response
|
||||
[DispatchNodeResponseKeyEnum.assistantResponses]?: ChatItemValueItemType[]; // Assistant response(Store to db)
|
||||
} & T;
|
||||
|
||||
/* Single node props */
|
||||
|
@@ -13,7 +13,7 @@ import { HttpNode468 } from './system/http468';
|
||||
import { ToolModule } from './system/tools';
|
||||
import { StopToolNode } from './system/stopTool';
|
||||
|
||||
import { RunAppModule } from './system/runApp/index';
|
||||
import { RunAppModule } from './system/abandoned/runApp/index';
|
||||
import { PluginInputModule } from './system/pluginInput';
|
||||
import { PluginOutputModule } from './system/pluginOutput';
|
||||
import { RunPluginModule } from './system/runPlugin';
|
||||
|
@@ -3,17 +3,17 @@ import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeOutputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '../../../node/constant';
|
||||
import { FlowNodeTemplateType } from '../../../type/node.d';
|
||||
} from '../../../../node/constant';
|
||||
import { FlowNodeTemplateType } from '../../../../type/node';
|
||||
import {
|
||||
WorkflowIOValueTypeEnum,
|
||||
NodeInputKeyEnum,
|
||||
NodeOutputKeyEnum,
|
||||
FlowNodeTemplateTypeEnum
|
||||
} from '../../../constants';
|
||||
import { Input_Template_History, Input_Template_UserChatInput } from '../../input';
|
||||
import { getHandleConfig } from '../../utils';
|
||||
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||
} from '../../../../constants';
|
||||
import { Input_Template_History, Input_Template_UserChatInput } from '../../../input';
|
||||
import { getHandleConfig } from '../../../utils';
|
||||
import { i18nT } from '../../../../../../../web/i18n/utils';
|
||||
|
||||
export const RunAppModule: FlowNodeTemplateType = {
|
||||
id: FlowNodeTypeEnum.runApp,
|
@@ -28,7 +28,7 @@ export type WorkflowTemplateBasicType = {
|
||||
};
|
||||
export type WorkflowTemplateType = {
|
||||
id: string;
|
||||
parentId?: string;
|
||||
parentId?: ParentIdType;
|
||||
isFolder?: boolean;
|
||||
|
||||
name: string;
|
||||
@@ -62,6 +62,8 @@ export type TemplateMarketListItemType = {
|
||||
|
||||
// system plugin
|
||||
export type SystemPluginTemplateItemType = WorkflowTemplateType & {
|
||||
customWorkflow?: string;
|
||||
|
||||
templateType: FlowNodeTemplateTypeEnum;
|
||||
isTool?: boolean;
|
||||
|
||||
|
@@ -32,6 +32,7 @@ import { IfElseResultEnum } from './template/system/ifElse/constant';
|
||||
import { RuntimeNodeItemType } from './runtime/type';
|
||||
import { getReferenceVariableValue } from './runtime/utils';
|
||||
import { Input_Template_History, Input_Template_UserChatInput } from './template/input';
|
||||
import { i18nT } from '../../../web/i18n/utils';
|
||||
|
||||
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
||||
return `${nodeId}-${type}-${key}`;
|
||||
@@ -254,8 +255,8 @@ export const appData2FlowNodeIO = ({
|
||||
id: NodeOutputKeyEnum.history,
|
||||
key: NodeOutputKeyEnum.history,
|
||||
required: true,
|
||||
label: 'core.module.output.label.New context',
|
||||
description: 'core.module.output.description.New context',
|
||||
label: i18nT('common:core.module.output.label.New context'),
|
||||
description: i18nT('common:core.module.output.description.New context'),
|
||||
valueType: WorkflowIOValueTypeEnum.chatHistory,
|
||||
valueDesc: chatHistoryValueDesc,
|
||||
type: FlowNodeOutputTypeEnum.static
|
||||
@@ -264,8 +265,8 @@ export const appData2FlowNodeIO = ({
|
||||
id: NodeOutputKeyEnum.answerText,
|
||||
key: NodeOutputKeyEnum.answerText,
|
||||
required: false,
|
||||
label: 'core.module.output.label.Ai response content',
|
||||
description: 'core.module.output.description.Ai response content',
|
||||
label: i18nT('common:core.module.output.label.Ai response content'),
|
||||
description: i18nT('common:core.module.output.description.Ai response content'),
|
||||
valueType: WorkflowIOValueTypeEnum.string,
|
||||
type: FlowNodeOutputTypeEnum.static
|
||||
}
|
||||
@@ -325,6 +326,9 @@ export const updatePluginInputByVariables = (
|
||||
);
|
||||
};
|
||||
|
||||
/* Remove pluginInput variables from global variables
|
||||
(completions api: Plugin input get value from global variables)
|
||||
*/
|
||||
export const removePluginInputVariables = (
|
||||
variables: Record<string, any>,
|
||||
nodes: RuntimeNodeItemType[]
|
||||
|
@@ -24,7 +24,8 @@ const SystemPluginSchema = new Schema({
|
||||
currentCost: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
customConfig: Object
|
||||
});
|
||||
|
||||
SystemPluginSchema.index({ pluginId: 1 });
|
||||
|
16
packages/service/core/app/plugin/type.d.ts
vendored
16
packages/service/core/app/plugin/type.d.ts
vendored
@@ -1,4 +1,8 @@
|
||||
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import {
|
||||
SystemPluginTemplateItemType,
|
||||
WorkflowTemplateBasicType
|
||||
} from '@fastgpt/global/core/workflow/type';
|
||||
|
||||
export type SystemPluginConfigSchemaType = {
|
||||
pluginId: string;
|
||||
@@ -7,4 +11,14 @@ export type SystemPluginConfigSchemaType = {
|
||||
currentCost: number;
|
||||
isActive: boolean;
|
||||
inputConfig: SystemPluginTemplateItemType['inputConfig'];
|
||||
|
||||
customConfig?: {
|
||||
name: string;
|
||||
avatar: string;
|
||||
intro?: string;
|
||||
version: string;
|
||||
weight?: number;
|
||||
workflow: WorkflowTemplateBasicType;
|
||||
templateType: FlowNodeTemplateTypeEnum;
|
||||
};
|
||||
};
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* Abandoned */
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/runApp/type';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/abandoned/runApp/type';
|
||||
import { dispatchWorkFlow } from '../index';
|
||||
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
@@ -11,7 +11,7 @@ import {
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { getHistories } from '../utils';
|
||||
import { filterSystemVariables, getHistories } from '../utils';
|
||||
import { chatValue2RuntimePrompt, runtimePrompt2ChatsValue } from '@fastgpt/global/core/chat/adapt';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { authAppByTmbId } from '../../../../support/permission/app/auth';
|
||||
@@ -34,10 +34,11 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
||||
query,
|
||||
node: { pluginId },
|
||||
workflowStreamResponse,
|
||||
params
|
||||
params,
|
||||
variables
|
||||
} = props;
|
||||
|
||||
const { userChatInput, history, ...variables } = params;
|
||||
const { userChatInput, history, ...childrenAppVariables } = params;
|
||||
if (!userChatInput) {
|
||||
return Promise.reject('Input is empty');
|
||||
}
|
||||
@@ -63,6 +64,13 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
||||
const chatHistories = getHistories(history, histories);
|
||||
const { files } = chatValue2RuntimePrompt(query);
|
||||
|
||||
// Concat variables
|
||||
const systemVariables = filterSystemVariables(variables);
|
||||
const childrenRunVariables = {
|
||||
...systemVariables,
|
||||
...childrenAppVariables
|
||||
};
|
||||
|
||||
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlow({
|
||||
...props,
|
||||
app: appData,
|
||||
@@ -76,7 +84,7 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
||||
files,
|
||||
text: userChatInput
|
||||
}),
|
||||
variables: variables
|
||||
variables: childrenRunVariables
|
||||
});
|
||||
|
||||
const completeMessages = chatHistories.concat([
|
@@ -31,7 +31,7 @@ import { dispatchAnswer } from './tools/answer';
|
||||
import { dispatchClassifyQuestion } from './agent/classifyQuestion';
|
||||
import { dispatchContentExtract } from './agent/extract';
|
||||
import { dispatchHttp468Request } from './tools/http468';
|
||||
import { dispatchAppRequest } from './tools/runApp';
|
||||
import { dispatchAppRequest } from './abandoned/runApp';
|
||||
import { dispatchQueryExtension } from './tools/queryExternsion';
|
||||
import { dispatchRunPlugin } from './plugin/run';
|
||||
import { dispatchPluginInput } from './plugin/runInput';
|
||||
@@ -63,7 +63,7 @@ import {
|
||||
InteractiveNodeResponseItemType,
|
||||
UserSelectInteractive
|
||||
} from '@fastgpt/global/core/workflow/template/system/userSelect/type';
|
||||
import { dispatchRunAppNode } from './agent/runAppModule';
|
||||
import { dispatchRunAppNode } from './agent/runApp';
|
||||
|
||||
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||
@@ -74,7 +74,6 @@ const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.classifyQuestion]: dispatchClassifyQuestion,
|
||||
[FlowNodeTypeEnum.contentExtract]: dispatchContentExtract,
|
||||
[FlowNodeTypeEnum.httpRequest468]: dispatchHttp468Request,
|
||||
[FlowNodeTypeEnum.runApp]: dispatchAppRequest,
|
||||
[FlowNodeTypeEnum.appModule]: dispatchRunAppNode,
|
||||
[FlowNodeTypeEnum.pluginModule]: dispatchRunPlugin,
|
||||
[FlowNodeTypeEnum.pluginInput]: dispatchPluginInput,
|
||||
@@ -95,7 +94,9 @@ const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.systemConfig]: dispatchSystemConfig,
|
||||
[FlowNodeTypeEnum.pluginConfig]: () => Promise.resolve(),
|
||||
[FlowNodeTypeEnum.emptyNode]: () => Promise.resolve(),
|
||||
[FlowNodeTypeEnum.globalVariable]: () => Promise.resolve()
|
||||
[FlowNodeTypeEnum.globalVariable]: () => Promise.resolve(),
|
||||
|
||||
[FlowNodeTypeEnum.runApp]: dispatchAppRequest // abandoned
|
||||
};
|
||||
|
||||
type Props = ChatDispatchProps & {
|
||||
|
@@ -9,10 +9,10 @@ import {
|
||||
storeNodes2RuntimeNodes
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { updateToolInputValue } from '../agent/runTool/utils';
|
||||
import { authPluginByTmbId } from '../../../../support/permission/app/auth';
|
||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { computedPluginUsage } from '../../../app/plugin/utils';
|
||||
import { filterSystemVariables } from '../utils';
|
||||
|
||||
type RunPluginProps = ModuleDispatchProps<{
|
||||
[key: string]: any;
|
||||
@@ -25,7 +25,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
||||
app: workflowApp,
|
||||
mode,
|
||||
teamId,
|
||||
params: data
|
||||
params: data // Plugin input
|
||||
} = props;
|
||||
|
||||
if (!pluginId) {
|
||||
@@ -41,32 +41,31 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
||||
|
||||
const plugin = await getPluginRuntimeById(pluginId);
|
||||
|
||||
// concat dynamic inputs
|
||||
const inputModule = plugin.nodes.find(
|
||||
(item) => item.flowNodeType === FlowNodeTypeEnum.pluginInput
|
||||
);
|
||||
if (!inputModule) return Promise.reject('Plugin error, It has no set input.');
|
||||
const runtimeNodes = storeNodes2RuntimeNodes(
|
||||
plugin.nodes,
|
||||
getWorkflowEntryNodeIds(plugin.nodes)
|
||||
).map((node) => {
|
||||
// Update plugin input value
|
||||
if (node.flowNodeType === FlowNodeTypeEnum.pluginInput) {
|
||||
return {
|
||||
...node,
|
||||
showStatus: false,
|
||||
inputs: node.inputs.map((input) => ({
|
||||
...input,
|
||||
value: data[input.key] ?? input.value
|
||||
}))
|
||||
};
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
showStatus: false
|
||||
};
|
||||
});
|
||||
|
||||
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlow({
|
||||
...props,
|
||||
runtimeNodes: storeNodes2RuntimeNodes(plugin.nodes, getWorkflowEntryNodeIds(plugin.nodes)).map(
|
||||
(node) => {
|
||||
if (node.flowNodeType === FlowNodeTypeEnum.pluginInput) {
|
||||
return {
|
||||
...node,
|
||||
showStatus: false,
|
||||
inputs: updateToolInputValue({
|
||||
inputs: node.inputs,
|
||||
params: data
|
||||
})
|
||||
};
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
showStatus: false
|
||||
};
|
||||
}
|
||||
),
|
||||
variables: filterSystemVariables(props.variables),
|
||||
runtimeNodes,
|
||||
runtimeEdges: initWorkflowEdgeStatus(plugin.edges)
|
||||
});
|
||||
|
||||
|
@@ -144,6 +144,15 @@ export const removeSystemVariable = (variables: Record<string, any>) => {
|
||||
|
||||
return copyVariables;
|
||||
};
|
||||
export const filterSystemVariables = (variables: Record<string, any>) => {
|
||||
return {
|
||||
appId: variables.appId,
|
||||
chatId: variables.chatId,
|
||||
responseChatItemId: variables.responseChatItemId,
|
||||
histories: variables.histories,
|
||||
cTime: variables.cTime
|
||||
};
|
||||
};
|
||||
|
||||
export const formatHttpError = (error: any) => {
|
||||
return {
|
||||
|
@@ -83,6 +83,7 @@ const RenderInput = () => {
|
||||
rounded={'md'}
|
||||
fontSize={'sm'}
|
||||
color={'myGray.600'}
|
||||
mb={4}
|
||||
>
|
||||
<Markdown source={chatConfig.instruction} />
|
||||
</Box>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { ModalBody, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/runApp/type';
|
||||
import type { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/abandoned/runApp/type';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import SelectOneResource from '@/components/common/folder/SelectOneResource';
|
||||
import {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { Box, Button, useDisclosure } from '@chakra-ui/react';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/runApp/type';
|
||||
import type { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/abandoned/runApp/type';
|
||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import SelectAppModal from '../../../../SelectAppModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
@@ -27,8 +27,10 @@ const refetchSystemPlugins = () => {
|
||||
const changeStream = MongoSystemPluginSchema.watch();
|
||||
|
||||
changeStream.on('change', async (change) => {
|
||||
try {
|
||||
getSystemPlugins(true);
|
||||
} catch (error) {}
|
||||
setTimeout(() => {
|
||||
try {
|
||||
getSystemPlugins(true);
|
||||
} catch (error) {}
|
||||
}, 5000);
|
||||
});
|
||||
};
|
||||
|
Reference in New Issue
Block a user