mirror of
https://github.com/labring/FastGPT.git
synced 2026-04-17 02:06:41 +08:00
feature: System plugin (#5131)
* feat: system Tool (#4959) * feat: independent system tool * chore: use ToolNode instead of PluginModule * chore: tools * chore: tools templateDir * refactor: templates * feat: flush code * chore: update template * refactor: migrate delay * feat: worker pool * chore: Dockerfile * docs: add tools.template.json * feat: auto flush system tools * fix: ts error * chore: create new pool temporarily * chore: system tool migration * chore: migration * fix: fix pnpm-workspace.yaml * chore: update pnpm-lock.yaml to integrate tool * chore(systemTool): chore * chore: add system plugin * chore(deps): update @fastgpt-sdk/plugin * fix: type error * chore: remove plugin package * chore: move pro plugins code to open source * feat: support system tool config input * fix: type error * perf: i18n * fix: cr * chore: update sdk * feat: system plugin cache * update mcp server (#5076) * update mcp server * fix: action * fix: dockerfile * fix: dockerfile * fix: dockerfile * fix: dockerfile * fix: dockerfile * fix: dockerfile * feat: system Tool (#4959) * feat: independent system tool * chore: use ToolNode instead of PluginModule * chore: tools * chore: tools templateDir * refactor: templates * feat: flush code * chore: update template * refactor: migrate delay * feat: worker pool * chore: Dockerfile * docs: add tools.template.json * feat: auto flush system tools * fix: ts error * chore: create new pool temporarily * chore: system tool migration * chore: migration * fix: fix pnpm-workspace.yaml * chore: update pnpm-lock.yaml to integrate tool * chore(systemTool): chore * chore: add system plugin * chore(deps): update @fastgpt-sdk/plugin * fix: type error * chore: remove plugin package * chore: move pro plugins code to open source * feat: support system tool config input * fix: type error * perf: i18n * fix: cr * chore: update sdk * feat: system plugin cache * perf: run tool * update package * perf: config key * fix: tool ini * tool config params * perf: workflow type * rename tools to agent * version list * perf: tool error * config secret ux * perf: config secret ux * fix: tool config field * add course to secret input * feat: support inputConfig switch (#5099) * feat: support inputConfig switch * deps: update @fastgpt-sdk/plugin * chore: update workflows * fix: inputType * fix: secret * add default value to node * update i18n * eslint * add precision to number input * feat: add number input and select * perf: number ux * fix: code * Proxies image requests to plugin service (#5111) * Proxies image requests to plugin service Adds a rewrite rule and API endpoint to proxy image requests to the plugin service. This allows the app to fetch images from the plugin's tools directory. It also adds the plugin base URL to the service's constants, so that it can use the plugin URL when proxying requests. * fix: update FastGPTPluginUrl to remove unnecessary API path * feat: update image proxy destination and add plugin image handler * Adapt plugin id * replace avatar * remove rewrite * fix: plugin avatar * update system tool doc * feat: system tool type * yml sh * yml sh * update doc * fix: simple app tool select * fix: switch ui * update pacakge * Yamljs (#5129) * update docker-compose configuration: bump fastgpt and fastgpt-plugin images, change minio host to service name, and adjust service dependencies * refactor: comment out port exposure in docker-compose configuration * update: uncomment port exposure in docker-compose configuration * update: change MINIO_HOST to use specific IP address in docker configuration * update: modify fastgpt-plugin image version in docker configuration * update readme * doc * remove --------- Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com> Co-authored-by: Theresa <63280168+sd0ric4@users.noreply.github.com>
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
"provider": "Doubao",
|
||||
"list": [
|
||||
{
|
||||
"model": "Doubao-Seed-1.6",
|
||||
"name": "Doubao-Seed-1.6",
|
||||
"model": "doubao-seed-1-6-250615",
|
||||
"name": "doubao-seed-1-6-250615",
|
||||
"maxContext": 220000,
|
||||
"maxResponse": 16000,
|
||||
"quoteMaxToken": 220000,
|
||||
@@ -24,8 +24,8 @@
|
||||
"type": "llm"
|
||||
},
|
||||
{
|
||||
"model": "Doubao-Seed-1.6-thinking",
|
||||
"name": "Doubao-Seed-1.6-thinking",
|
||||
"model": "doubao-seed-1-6-flash-250615",
|
||||
"name": "doubao-seed-1-6-flash-250615",
|
||||
"maxContext": 220000,
|
||||
"maxResponse": 16000,
|
||||
"quoteMaxToken": 220000,
|
||||
@@ -46,8 +46,8 @@
|
||||
"type": "llm"
|
||||
},
|
||||
{
|
||||
"model": "Doubao-Seed-1.6-flash",
|
||||
"name": "Doubao-Seed-1.6-flash",
|
||||
"model": "doubao-seed-1-6-thinking-250615",
|
||||
"name": "doubao-seed-1-6-thinking-250615",
|
||||
"maxContext": 220000,
|
||||
"maxResponse": 16000,
|
||||
"quoteMaxToken": 220000,
|
||||
|
||||
@@ -3,7 +3,8 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { MongoApp } from './schema';
|
||||
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import { storeSecretValue } from '../../common/secret/utils';
|
||||
import { encryptSecretValue, storeSecretValue } from '../../common/secret/utils';
|
||||
import { SystemToolInputTypeEnum } from '@fastgpt/global/core/app/systemTool/constants';
|
||||
|
||||
export const beforeUpdateAppFormat = ({ nodes }: { nodes?: StoreNodeItemType[] }) => {
|
||||
if (!nodes) return;
|
||||
@@ -14,6 +15,17 @@ export const beforeUpdateAppFormat = ({ nodes }: { nodes?: StoreNodeItemType[] }
|
||||
if (input.key === NodeInputKeyEnum.headerSecret && typeof input.value === 'object') {
|
||||
input.value = storeSecretValue(input.value);
|
||||
}
|
||||
if (input.key === NodeInputKeyEnum.systemInputConfig && typeof input.value === 'object') {
|
||||
input.inputList?.forEach((inputItem) => {
|
||||
if (
|
||||
inputItem.inputType === 'secret' &&
|
||||
input.value?.type === SystemToolInputTypeEnum.manual &&
|
||||
input.value?.value
|
||||
) {
|
||||
input.value.value[inputItem.key] = encryptSecretValue(input.value.value[inputItem.key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Format dataset search
|
||||
|
||||
@@ -6,31 +6,42 @@ import {
|
||||
toolData2FlowNodeIO,
|
||||
toolSetData2FlowNodeIO
|
||||
} from '@fastgpt/global/core/workflow/utils';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { getHandleConfig } from '@fastgpt/global/core/workflow/template/utils';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { MongoApp } from '../schema';
|
||||
import { type SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import { getSystemPluginTemplates } from '../../../../plugins/register';
|
||||
import type { localeType } from '@fastgpt/global/common/i18n/type';
|
||||
import { parseI18nString } from '@fastgpt/global/common/i18n/utils';
|
||||
import type { WorkflowTemplateBasicType } from '@fastgpt/global/core/workflow/type';
|
||||
import { type SystemPluginTemplateItemType } from '@fastgpt/global/core/app/plugin/type';
|
||||
import {
|
||||
checkIsLatestVersion,
|
||||
getAppLatestVersion,
|
||||
getAppVersionById
|
||||
} from '../version/controller';
|
||||
import { type PluginRuntimeType } from '@fastgpt/global/core/plugin/type';
|
||||
import { type PluginRuntimeType } from '@fastgpt/global/core/app/plugin/type';
|
||||
import { MongoSystemPlugin } from './systemPluginSchema';
|
||||
import { PluginErrEnum } from '@fastgpt/global/common/error/code/plugin';
|
||||
import { Types } from 'mongoose';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
|
||||
import {
|
||||
FlowNodeTemplateTypeEnum,
|
||||
NodeInputKeyEnum
|
||||
} from '@fastgpt/global/core/workflow/constants';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { getSystemToolList } from '../tool/api';
|
||||
import { Types } from '../../../common/mongo';
|
||||
import type { SystemPluginConfigSchemaType } from './type';
|
||||
import type {
|
||||
FlowNodeInputItemType,
|
||||
FlowNodeOutputItemType
|
||||
} from '@fastgpt/global/core/workflow/type/io';
|
||||
import { isProduction } from '@fastgpt/global/common/system/constants';
|
||||
|
||||
/*
|
||||
/**
|
||||
plugin id rule:
|
||||
personal: id
|
||||
community: community-id
|
||||
commercial: commercial-id
|
||||
- personal: ObjectId
|
||||
- commercial: commercial-ObjectId
|
||||
- systemtool: systemTool-id
|
||||
(deprecated) community: community-id
|
||||
*/
|
||||
export function splitCombineToolId(id: string) {
|
||||
export function splitCombinePluginId(id: string) {
|
||||
const splitRes = id.split('-');
|
||||
if (splitRes.length === 1) {
|
||||
// app id
|
||||
@@ -40,92 +51,116 @@ export function splitCombineToolId(id: string) {
|
||||
};
|
||||
}
|
||||
|
||||
const [source, pluginId] = id.split('-') as [PluginSourceEnum, string];
|
||||
const [source, pluginId] = id.split('-') as [PluginSourceEnum, string | undefined];
|
||||
if (!source || !pluginId) throw new Error('pluginId not found');
|
||||
|
||||
// 兼容4.10.0 之前的插件
|
||||
if (source === 'community' || id === 'commercial-dalle3') {
|
||||
return {
|
||||
source: PluginSourceEnum.systemTool,
|
||||
pluginId: `${PluginSourceEnum.systemTool}-${pluginId}`
|
||||
};
|
||||
}
|
||||
|
||||
return { source, pluginId: id };
|
||||
}
|
||||
|
||||
type ChildAppType = SystemPluginTemplateItemType & { teamId?: string; tmbId?: string };
|
||||
type ChildAppType = SystemPluginTemplateItemType & {
|
||||
teamId?: string;
|
||||
tmbId?: string;
|
||||
workflow?: WorkflowTemplateBasicType;
|
||||
versionLabel?: string; // Auto computed
|
||||
isLatestVersion?: boolean; // Auto computed
|
||||
};
|
||||
|
||||
const getSystemPluginTemplateById = async (
|
||||
export const getSystemPluginByIdAndVersionId = async (
|
||||
pluginId: string,
|
||||
versionId?: string
|
||||
): Promise<ChildAppType> => {
|
||||
const item = getSystemPluginTemplates().find((plugin) => plugin.id === pluginId);
|
||||
if (!item) return Promise.reject(PluginErrEnum.unExist);
|
||||
const plugin = await (async (): Promise<ChildAppType> => {
|
||||
const plugin = await getSystemPluginById(pluginId);
|
||||
|
||||
const plugin = cloneDeep(item);
|
||||
// Admin selected system tool
|
||||
if (plugin.associatedPluginId) {
|
||||
// The verification plugin is set as a system plugin
|
||||
const systemPlugin = await MongoSystemPlugin.findOne(
|
||||
{ pluginId: plugin.id, 'customConfig.associatedPluginId': plugin.associatedPluginId },
|
||||
'associatedPluginId'
|
||||
).lean();
|
||||
if (!systemPlugin) return Promise.reject(PluginErrEnum.unExist);
|
||||
|
||||
if (plugin.associatedPluginId) {
|
||||
// The verification plugin is set as a system plugin
|
||||
const systemPlugin = await MongoSystemPlugin.findOne(
|
||||
{ pluginId: plugin.id, 'customConfig.associatedPluginId': plugin.associatedPluginId },
|
||||
'associatedPluginId'
|
||||
).lean();
|
||||
if (!systemPlugin) return Promise.reject(PluginErrEnum.unExist);
|
||||
const app = await MongoApp.findById(plugin.associatedPluginId).lean();
|
||||
if (!app) return Promise.reject(PluginErrEnum.unExist);
|
||||
|
||||
const app = await MongoApp.findById(plugin.associatedPluginId).lean();
|
||||
if (!app) return Promise.reject(PluginErrEnum.unExist);
|
||||
const version = versionId
|
||||
? await getAppVersionById({
|
||||
appId: plugin.associatedPluginId,
|
||||
versionId,
|
||||
app
|
||||
})
|
||||
: await getAppLatestVersion(plugin.associatedPluginId, app);
|
||||
if (!version.versionId) return Promise.reject('App version not found');
|
||||
const isLatest = version.versionId
|
||||
? await checkIsLatestVersion({
|
||||
appId: plugin.associatedPluginId,
|
||||
versionId: version.versionId
|
||||
})
|
||||
: true;
|
||||
|
||||
return {
|
||||
...plugin,
|
||||
workflow: {
|
||||
nodes: version.nodes,
|
||||
edges: version.edges,
|
||||
chatConfig: version.chatConfig
|
||||
},
|
||||
version: versionId ? version?.versionId : '',
|
||||
versionLabel: version?.versionName,
|
||||
isLatestVersion: isLatest,
|
||||
teamId: String(app.teamId),
|
||||
tmbId: String(app.tmbId)
|
||||
};
|
||||
}
|
||||
|
||||
const version = versionId
|
||||
? await getAppVersionById({
|
||||
appId: plugin.associatedPluginId,
|
||||
versionId,
|
||||
app
|
||||
})
|
||||
: await getAppLatestVersion(plugin.associatedPluginId, app);
|
||||
if (!version.versionId) return Promise.reject('App version not found');
|
||||
const isLatest = version.versionId
|
||||
? await checkIsLatestVersion({
|
||||
appId: plugin.associatedPluginId,
|
||||
versionId: version.versionId
|
||||
})
|
||||
: true;
|
||||
? plugin.versionList?.find((item) => item.value === versionId)
|
||||
: plugin.versionList?.[0];
|
||||
const lastVersion = plugin.versionList?.[0];
|
||||
|
||||
return {
|
||||
...plugin,
|
||||
workflow: {
|
||||
nodes: version.nodes,
|
||||
edges: version.edges,
|
||||
chatConfig: version.chatConfig
|
||||
},
|
||||
version: versionId ? version?.versionId : '',
|
||||
versionLabel: version?.versionName,
|
||||
isLatestVersion: isLatest,
|
||||
teamId: String(app.teamId),
|
||||
tmbId: String(app.tmbId)
|
||||
version: versionId ? version?.value : '',
|
||||
versionLabel: version ? version?.value : '',
|
||||
isLatestVersion: !version || !lastVersion || version.value === lastVersion?.value
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
...plugin,
|
||||
version: undefined,
|
||||
isLatestVersion: true
|
||||
};
|
||||
return plugin;
|
||||
};
|
||||
|
||||
/* Format plugin to workflow preview node data */
|
||||
export async function getChildAppPreviewNode({
|
||||
appId,
|
||||
versionId
|
||||
versionId,
|
||||
lang = 'en'
|
||||
}: {
|
||||
appId: string;
|
||||
versionId?: string;
|
||||
lang?: localeType;
|
||||
}): Promise<FlowNodeTemplateType> {
|
||||
const app: ChildAppType = await (async () => {
|
||||
const { source, pluginId } = splitCombineToolId(appId);
|
||||
const { source, pluginId } = splitCombinePluginId(appId);
|
||||
|
||||
const app: ChildAppType = await (async () => {
|
||||
if (source === PluginSourceEnum.personal) {
|
||||
const item = await MongoApp.findById(appId).lean();
|
||||
const item = await MongoApp.findById(pluginId).lean();
|
||||
if (!item) return Promise.reject(PluginErrEnum.unExist);
|
||||
|
||||
const version = await getAppVersionById({ appId, versionId, app: item });
|
||||
const version = await getAppVersionById({ appId: pluginId, versionId, app: item });
|
||||
|
||||
const isLatest =
|
||||
version.versionId && Types.ObjectId.isValid(version.versionId)
|
||||
? await checkIsLatestVersion({
|
||||
appId,
|
||||
appId: pluginId,
|
||||
versionId: version.versionId
|
||||
})
|
||||
: true;
|
||||
@@ -154,38 +189,53 @@ export async function getChildAppPreviewNode({
|
||||
pluginOrder: 0
|
||||
};
|
||||
} else {
|
||||
return getSystemPluginTemplateById(pluginId, versionId);
|
||||
return getSystemPluginByIdAndVersionId(pluginId, versionId);
|
||||
}
|
||||
})();
|
||||
|
||||
const isPlugin = !!app.workflow.nodes.find(
|
||||
(node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput
|
||||
);
|
||||
|
||||
const isTool =
|
||||
!!app.workflow.nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.tool) &&
|
||||
app.workflow.nodes.length === 1;
|
||||
|
||||
const isToolSet =
|
||||
!!app.workflow.nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.toolSet) &&
|
||||
app.workflow.nodes.length === 1;
|
||||
|
||||
const { flowNodeType, nodeIOConfig } = (() => {
|
||||
if (isToolSet)
|
||||
return {
|
||||
flowNodeType: FlowNodeTypeEnum.toolSet,
|
||||
nodeIOConfig: toolSetData2FlowNodeIO({ nodes: app.workflow.nodes })
|
||||
};
|
||||
if (isTool)
|
||||
const { flowNodeType, nodeIOConfig } = await (async () => {
|
||||
if (source === PluginSourceEnum.systemTool) {
|
||||
return {
|
||||
flowNodeType: FlowNodeTypeEnum.tool,
|
||||
nodeIOConfig: toolData2FlowNodeIO({ nodes: app.workflow.nodes })
|
||||
nodeIOConfig: {
|
||||
inputs: app.inputs!,
|
||||
outputs: app.outputs!,
|
||||
toolConfig: {
|
||||
systemTool: {
|
||||
toolId: app.id
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (isPlugin)
|
||||
}
|
||||
|
||||
if (!!app.workflow.nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)) {
|
||||
return {
|
||||
flowNodeType: FlowNodeTypeEnum.pluginModule,
|
||||
nodeIOConfig: pluginData2FlowNodeIO({ nodes: app.workflow.nodes })
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
!!app.workflow.nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.toolSet) &&
|
||||
app.workflow.nodes.length === 1
|
||||
) {
|
||||
return {
|
||||
flowNodeType: FlowNodeTypeEnum.toolSet,
|
||||
nodeIOConfig: toolSetData2FlowNodeIO({ nodes: app.workflow.nodes })
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
!!app.workflow.nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.tool) &&
|
||||
app.workflow.nodes.length === 1
|
||||
) {
|
||||
return {
|
||||
flowNodeType: FlowNodeTypeEnum.tool,
|
||||
nodeIOConfig: toolData2FlowNodeIO({ nodes: app.workflow.nodes })
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
flowNodeType: FlowNodeTypeEnum.appModule,
|
||||
nodeIOConfig: appData2FlowNodeIO({ chatConfig: app.workflow.chatConfig })
|
||||
@@ -198,45 +248,46 @@ export async function getChildAppPreviewNode({
|
||||
templateType: app.templateType,
|
||||
flowNodeType,
|
||||
avatar: app.avatar,
|
||||
name: app.name,
|
||||
intro: app.intro,
|
||||
name: parseI18nString(app.name, lang),
|
||||
intro: parseI18nString(app.intro, lang),
|
||||
courseUrl: app.courseUrl,
|
||||
userGuide: app.userGuide,
|
||||
showStatus: app.showStatus,
|
||||
showStatus: true,
|
||||
isTool: true,
|
||||
|
||||
version: app.version,
|
||||
versionLabel: app.versionLabel,
|
||||
isLatestVersion: app.isLatestVersion,
|
||||
showSourceHandle: true,
|
||||
showTargetHandle: true,
|
||||
|
||||
currentCost: app.currentCost,
|
||||
hasTokenFee: app.hasTokenFee,
|
||||
hasSystemSecret: app.hasSystemSecret,
|
||||
|
||||
sourceHandle: isToolSet
|
||||
? getHandleConfig(false, false, false, false)
|
||||
: getHandleConfig(true, true, true, true),
|
||||
targetHandle: isToolSet
|
||||
? getHandleConfig(false, false, false, false)
|
||||
: getHandleConfig(true, true, true, true),
|
||||
...nodeIOConfig
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
Get runtime plugin data
|
||||
System plugin: plugin id
|
||||
Personal plugin: Version id
|
||||
*/
|
||||
export async function getChildAppRuntimeById(
|
||||
id: string,
|
||||
versionId?: string
|
||||
versionId?: string,
|
||||
lang: localeType = 'en'
|
||||
): Promise<PluginRuntimeType> {
|
||||
const app = await (async () => {
|
||||
const { source, pluginId } = splitCombineToolId(id);
|
||||
const { source, pluginId } = splitCombinePluginId(id);
|
||||
|
||||
if (source === PluginSourceEnum.personal) {
|
||||
const item = await MongoApp.findById(id).lean();
|
||||
const item = await MongoApp.findById(pluginId).lean();
|
||||
if (!item) return Promise.reject(PluginErrEnum.unExist);
|
||||
|
||||
const version = await getAppVersionById({
|
||||
appId: id,
|
||||
appId: pluginId,
|
||||
versionId,
|
||||
app: item
|
||||
});
|
||||
@@ -262,8 +313,7 @@ export async function getChildAppRuntimeById(
|
||||
pluginOrder: 0
|
||||
};
|
||||
} else {
|
||||
// System
|
||||
return getSystemPluginTemplateById(pluginId, versionId);
|
||||
return getSystemPluginByIdAndVersionId(pluginId, versionId);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -271,12 +321,171 @@ export async function getChildAppRuntimeById(
|
||||
id: app.id,
|
||||
teamId: app.teamId,
|
||||
tmbId: app.tmbId,
|
||||
name: app.name,
|
||||
avatar: app.avatar,
|
||||
showStatus: app.showStatus,
|
||||
name: parseI18nString(app.name, lang),
|
||||
avatar: app.avatar || '',
|
||||
showStatus: true,
|
||||
currentCost: app.currentCost,
|
||||
nodes: app.workflow.nodes,
|
||||
edges: app.workflow.edges,
|
||||
hasTokenFee: app.hasTokenFee
|
||||
};
|
||||
}
|
||||
|
||||
const dbPluginFormat = (item: SystemPluginConfigSchemaType): SystemPluginTemplateItemType => {
|
||||
const { name, avatar, intro, version, weight, templateType, associatedPluginId, userGuide } =
|
||||
item.customConfig!;
|
||||
|
||||
return {
|
||||
id: item.pluginId,
|
||||
isActive: item.isActive,
|
||||
isFolder: false,
|
||||
parentId: null,
|
||||
author: item.customConfig?.author || '',
|
||||
version,
|
||||
name,
|
||||
avatar,
|
||||
intro,
|
||||
weight,
|
||||
templateType,
|
||||
originCost: item.originCost,
|
||||
currentCost: item.currentCost,
|
||||
hasTokenFee: item.hasTokenFee,
|
||||
pluginOrder: item.pluginOrder,
|
||||
associatedPluginId,
|
||||
userGuide,
|
||||
workflow: {
|
||||
nodes: [],
|
||||
edges: []
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/* FastsGPT-Pluign api: */
|
||||
function getCachedSystemPlugins() {
|
||||
if (!global.systemPlugins_cache) {
|
||||
global.systemPlugins_cache = {
|
||||
expires: 0,
|
||||
data: [] as SystemPluginTemplateItemType[]
|
||||
};
|
||||
}
|
||||
return global.systemPlugins_cache;
|
||||
}
|
||||
|
||||
const cleanSystemPluginCache = () => {
|
||||
global.systemPlugins_cache = undefined;
|
||||
};
|
||||
|
||||
export const refetchSystemPlugins = () => {
|
||||
const changeStream = MongoSystemPlugin.watch();
|
||||
|
||||
changeStream.on('change', () => {
|
||||
try {
|
||||
cleanSystemPluginCache();
|
||||
} catch (error) {}
|
||||
});
|
||||
};
|
||||
|
||||
export const getSystemPlugins = async (): Promise<SystemPluginTemplateItemType[]> => {
|
||||
if (getCachedSystemPlugins().expires > Date.now() && isProduction) {
|
||||
return getCachedSystemPlugins().data;
|
||||
} else {
|
||||
const tools = await getSystemToolList();
|
||||
|
||||
// 从数据库里加载插件配置进行替换
|
||||
const systemPluginsArray = await MongoSystemPlugin.find({}).lean();
|
||||
const systemPlugins = new Map(systemPluginsArray.map((plugin) => [plugin.pluginId, plugin]));
|
||||
|
||||
tools.forEach((tool) => {
|
||||
// 如果有插件的配置信息,则需要进行替换
|
||||
const dbPluginConfig = systemPlugins.get(tool.id);
|
||||
|
||||
if (dbPluginConfig) {
|
||||
const children = tools.filter((item) => item.parentId === tool.id);
|
||||
const list = [tool, ...children];
|
||||
list.forEach((item) => {
|
||||
item.isActive = dbPluginConfig.isActive ?? item.isActive ?? true;
|
||||
item.originCost = dbPluginConfig.originCost ?? 0;
|
||||
item.currentCost = dbPluginConfig.currentCost ?? 0;
|
||||
item.hasTokenFee = dbPluginConfig.hasTokenFee ?? false;
|
||||
item.pluginOrder = dbPluginConfig.pluginOrder ?? 0;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const formatTools = tools.map<SystemPluginTemplateItemType>((item) => {
|
||||
const dbPluginConfig = systemPlugins.get(item.id);
|
||||
const inputs = item.versionList[0]?.inputs as FlowNodeInputItemType[];
|
||||
const outputs = item.versionList[0]?.outputs as FlowNodeOutputItemType[];
|
||||
|
||||
return {
|
||||
isActive: item.isActive,
|
||||
id: item.id,
|
||||
parentId: item.parentId,
|
||||
isFolder: tools.some((tool) => tool.parentId === item.id),
|
||||
name: item.name,
|
||||
avatar: item.avatar,
|
||||
intro: item.intro,
|
||||
author: item.author,
|
||||
courseUrl: item.courseUrl,
|
||||
showStatus: true,
|
||||
weight: item.weight,
|
||||
templateType: item.templateType,
|
||||
originCost: item.originCost,
|
||||
currentCost: item.currentCost,
|
||||
hasTokenFee: item.hasTokenFee,
|
||||
pluginOrder: item.pluginOrder,
|
||||
|
||||
workflow: {
|
||||
nodes: [],
|
||||
edges: []
|
||||
},
|
||||
versionList: item.versionList,
|
||||
inputs,
|
||||
outputs,
|
||||
|
||||
inputList: inputs?.find((input) => input.key === NodeInputKeyEnum.systemInputConfig)
|
||||
?.inputList as any,
|
||||
hasSystemSecret: !!dbPluginConfig?.inputListVal
|
||||
};
|
||||
});
|
||||
|
||||
const dbPlugins = systemPluginsArray
|
||||
.filter((item) => item.customConfig)
|
||||
.map((item) => dbPluginFormat(item));
|
||||
|
||||
const plugins = [...formatTools, ...dbPlugins];
|
||||
plugins.sort((a, b) => (a.pluginOrder ?? 0) - (b.pluginOrder ?? 0));
|
||||
|
||||
global.systemPlugins_cache = {
|
||||
expires: Date.now() + 30 * 60 * 1000, // 30 minutes
|
||||
data: plugins
|
||||
};
|
||||
|
||||
return plugins;
|
||||
}
|
||||
};
|
||||
|
||||
export const getSystemPluginById = async (id: string): Promise<SystemPluginTemplateItemType> => {
|
||||
const { source, pluginId } = splitCombinePluginId(id);
|
||||
if (source === PluginSourceEnum.systemTool) {
|
||||
const tools = await getSystemPlugins();
|
||||
const tool = tools.find((item) => item.id === pluginId);
|
||||
if (tool) {
|
||||
return tool;
|
||||
}
|
||||
return Promise.reject(PluginErrEnum.unExist);
|
||||
}
|
||||
|
||||
const dbPlugin = await MongoSystemPlugin.findOne({ pluginId }).lean();
|
||||
if (!dbPlugin) return Promise.reject(PluginErrEnum.unExist);
|
||||
return dbPluginFormat(dbPlugin);
|
||||
};
|
||||
|
||||
declare global {
|
||||
var systemPlugins_cache:
|
||||
| {
|
||||
expires: number;
|
||||
data: SystemPluginTemplateItemType[];
|
||||
}
|
||||
| undefined;
|
||||
}
|
||||
|
||||
@@ -12,10 +12,6 @@ const SystemPluginSchema = new Schema({
|
||||
isActive: {
|
||||
type: Boolean
|
||||
},
|
||||
inputConfig: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
originCost: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@@ -32,7 +28,11 @@ const SystemPluginSchema = new Schema({
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
customConfig: Object
|
||||
customConfig: Object,
|
||||
inputListVal: Object,
|
||||
|
||||
// @deprecated
|
||||
inputConfig: Array
|
||||
});
|
||||
|
||||
SystemPluginSchema.index({ pluginId: 1 });
|
||||
|
||||
17
packages/service/core/app/plugin/type.d.ts
vendored
17
packages/service/core/app/plugin/type.d.ts
vendored
@@ -1,9 +1,6 @@
|
||||
import { SystemPluginListItemType } from '@fastgpt/global/core/app/type';
|
||||
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type {
|
||||
SystemPluginTemplateItemType,
|
||||
WorkflowTemplateBasicType
|
||||
} from '@fastgpt/global/core/workflow/type';
|
||||
import type { WorkflowTemplateBasicType } from '@fastgpt/global/core/workflow/type';
|
||||
|
||||
export type SystemPluginConfigSchemaType = {
|
||||
pluginId: string;
|
||||
@@ -13,7 +10,6 @@ export type SystemPluginConfigSchemaType = {
|
||||
hasTokenFee: boolean;
|
||||
isActive: boolean;
|
||||
pluginOrder: number;
|
||||
inputConfig?: SystemPluginTemplateItemType['inputConfig'];
|
||||
|
||||
customConfig?: {
|
||||
name: string;
|
||||
@@ -21,12 +17,21 @@ export type SystemPluginConfigSchemaType = {
|
||||
intro?: string;
|
||||
version: string;
|
||||
weight?: number;
|
||||
workflow: WorkflowTemplateBasicType;
|
||||
templateType: string;
|
||||
associatedPluginId: string;
|
||||
userGuide: string;
|
||||
author?: string;
|
||||
};
|
||||
inputListVal?: Record<string, any>;
|
||||
|
||||
// @deprecated
|
||||
inputConfig?: {
|
||||
// Render config input form. Find the corresponding node and replace the variable directly
|
||||
key: string;
|
||||
label: string;
|
||||
description: string;
|
||||
value?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type TGroupType = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import { type PluginRuntimeType } from '@fastgpt/global/core/plugin/type';
|
||||
import { splitCombineToolId } from './controller';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||
import { type PluginRuntimeType } from '@fastgpt/global/core/app/plugin/type';
|
||||
import { splitCombinePluginId } from './controller';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
|
||||
|
||||
/*
|
||||
Plugin points calculation:
|
||||
@@ -20,7 +20,7 @@ export const computedPluginUsage = async ({
|
||||
childrenUsage: ChatNodeUsageType[];
|
||||
error?: boolean;
|
||||
}) => {
|
||||
const { source } = splitCombineToolId(plugin.id);
|
||||
const { source } = splitCombinePluginId(plugin.id);
|
||||
const childrenUsages = childrenUsage.reduce((sum, item) => sum + (item.totalPoints || 0), 0);
|
||||
|
||||
if (source !== PluginSourceEnum.personal) {
|
||||
|
||||
51
packages/service/core/app/tool/api.ts
Normal file
51
packages/service/core/app/tool/api.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import createClient, { type SystemVarType } from '@fastgpt-sdk/plugin';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
|
||||
|
||||
const client = createClient({
|
||||
baseUrl: process.env.PLUGIN_BASE_URL || '',
|
||||
token: process.env.PLUGIN_TOKEN || ''
|
||||
});
|
||||
|
||||
export async function getSystemToolList() {
|
||||
const res = await client.tool.list();
|
||||
|
||||
if (res.status === 200) {
|
||||
return res.body.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
id: `${PluginSourceEnum.systemTool}-${item.id}`,
|
||||
parentId: item.parentId ? `${PluginSourceEnum.systemTool}-${item.parentId}` : undefined,
|
||||
avatar:
|
||||
item.avatar && item.avatar.startsWith('/imgs/tools/')
|
||||
? `/api/system/pluginImgs/${item.avatar.replace('/imgs/tools/', '')}`
|
||||
: item.avatar
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(res.body);
|
||||
}
|
||||
|
||||
export async function runTool({
|
||||
toolId,
|
||||
inputs,
|
||||
systemVar
|
||||
}: {
|
||||
toolId: string;
|
||||
inputs: Record<string, any>;
|
||||
systemVar: SystemVarType;
|
||||
}) {
|
||||
const res = await client.tool.run({
|
||||
body: {
|
||||
toolId,
|
||||
inputs,
|
||||
systemVar
|
||||
}
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.body.output) {
|
||||
return res.body.output;
|
||||
} else {
|
||||
return Promise.reject(res.body);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@ import { getEmbeddingModel } from '../ai/model';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import { getChildAppPreviewNode, splitCombineToolId } from './plugin/controller';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||
import { getChildAppPreviewNode, splitCombinePluginId } from './plugin/controller';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
|
||||
import { authAppByTmbId } from '../../support/permission/app/auth';
|
||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
@@ -46,19 +46,19 @@ export async function rewriteAppWorkflowToDetail({
|
||||
await Promise.all(
|
||||
nodes.map(async (node) => {
|
||||
if (!node.pluginId) return;
|
||||
const { source } = splitCombineToolId(node.pluginId);
|
||||
const { source, pluginId } = splitCombinePluginId(node.pluginId);
|
||||
|
||||
try {
|
||||
const [preview] = await Promise.all([
|
||||
getChildAppPreviewNode({
|
||||
appId: node.pluginId,
|
||||
appId: pluginId,
|
||||
versionId: node.version
|
||||
}),
|
||||
...(source === PluginSourceEnum.personal
|
||||
? [
|
||||
authAppByTmbId({
|
||||
tmbId: ownerTmbId,
|
||||
appId: node.pluginId,
|
||||
appId: pluginId,
|
||||
per: ReadPermissionVal
|
||||
})
|
||||
]
|
||||
@@ -75,6 +75,10 @@ export async function rewriteAppWorkflowToDetail({
|
||||
node.versionLabel = preview.versionLabel;
|
||||
node.isLatestVersion = preview.isLatestVersion;
|
||||
node.version = preview.version;
|
||||
|
||||
node.currentCost = preview.currentCost;
|
||||
node.hasTokenFee = preview.hasTokenFee;
|
||||
node.hasSystemSecret = preview.hasSystemSecret;
|
||||
} catch (error) {
|
||||
node.pluginData = {
|
||||
error: getErrText(error)
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import { pluginTypeMap } from '@fastgpt/global/core/plugin/constants';
|
||||
import { connectionMongo, type Model } from '../../common/mongo';
|
||||
const { Schema, model, models } = connectionMongo;
|
||||
import type { PluginItemSchema } from '@fastgpt/global/core/plugin/type.d';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
|
||||
export const PluginCollectionName = 'plugins';
|
||||
|
||||
const PluginSchema = new Schema({
|
||||
parentId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: PluginCollectionName,
|
||||
default: null
|
||||
},
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
required: true
|
||||
},
|
||||
tmbId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamMemberCollectionName,
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
enum: Object.keys(pluginTypeMap),
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
default: '/icon/logo.svg'
|
||||
},
|
||||
intro: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
updateTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
modules: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
edges: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
metadata: {
|
||||
type: {
|
||||
pluginUid: String,
|
||||
apiSchemaStr: String,
|
||||
customHeaders: String
|
||||
}
|
||||
},
|
||||
version: {
|
||||
type: String,
|
||||
enum: ['v1', 'v2']
|
||||
},
|
||||
nodeVersion: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
inited: Boolean
|
||||
});
|
||||
|
||||
try {
|
||||
PluginSchema.index({ type: 1, init: 1 });
|
||||
PluginSchema.index({ teamId: 1, parentId: 1 });
|
||||
PluginSchema.index({ teamId: 1, name: 1, intro: 1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoPlugin: Model<PluginItemSchema> =
|
||||
models[PluginCollectionName] || model(PluginCollectionName, PluginSchema);
|
||||
MongoPlugin.syncIndexes();
|
||||
6
packages/service/core/plugin/type.d.ts
vendored
6
packages/service/core/plugin/type.d.ts
vendored
@@ -1,6 +0,0 @@
|
||||
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
|
||||
import type { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||
|
||||
declare global {
|
||||
var communityPlugins: SystemPluginTemplateItemType[];
|
||||
}
|
||||
@@ -19,11 +19,7 @@ import {
|
||||
getLLMDefaultUsage
|
||||
} from '@fastgpt/global/core/ai/constants';
|
||||
import { dispatchWorkFlow } from '../../index';
|
||||
import {
|
||||
type DispatchToolModuleProps,
|
||||
type RunToolResponse,
|
||||
type ToolNodeItemType
|
||||
} from './type.d';
|
||||
import { type DispatchToolModuleProps, type RunToolResponse, type ToolNodeItemType } from './type';
|
||||
import json5 from 'json5';
|
||||
import { type DispatchFlowResponse, type WorkflowResponseType } from '../../type';
|
||||
import { countGptMessagesTokens } from '../../../../../common/string/tiktoken/index';
|
||||
@@ -8,7 +8,7 @@ import type {
|
||||
import { getLLMModel } from '../../../../ai/model';
|
||||
import { filterToolNodeIdByEdges, getHistories } from '../../utils';
|
||||
import { runToolWithToolChoice } from './toolChoice';
|
||||
import { type DispatchToolModuleProps, type ToolNodeItemType } from './type.d';
|
||||
import { type DispatchToolModuleProps, type ToolNodeItemType } from './type';
|
||||
import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import {
|
||||
@@ -14,11 +14,7 @@ import {
|
||||
getLLMDefaultUsage
|
||||
} from '@fastgpt/global/core/ai/constants';
|
||||
import { dispatchWorkFlow } from '../../index';
|
||||
import {
|
||||
type DispatchToolModuleProps,
|
||||
type RunToolResponse,
|
||||
type ToolNodeItemType
|
||||
} from './type.d';
|
||||
import { type DispatchToolModuleProps, type RunToolResponse, type ToolNodeItemType } from './type';
|
||||
import json5 from 'json5';
|
||||
import { countGptMessagesTokens } from '../../../../../common/string/tiktoken/index';
|
||||
import {
|
||||
@@ -15,11 +15,7 @@ import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/cons
|
||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
||||
import { dispatchWorkFlow } from '../../index';
|
||||
import {
|
||||
type DispatchToolModuleProps,
|
||||
type RunToolResponse,
|
||||
type ToolNodeItemType
|
||||
} from './type.d';
|
||||
import { type DispatchToolModuleProps, type RunToolResponse, type ToolNodeItemType } from './type';
|
||||
import json5 from 'json5';
|
||||
import { type DispatchFlowResponse, type WorkflowResponseType } from '../../type';
|
||||
import { countGptMessagesTokens } from '../../../../../common/string/tiktoken/index';
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import type { DispatchFlowResponse } from '../../type.d';
|
||||
import type { DispatchFlowResponse } from '../../type';
|
||||
import type { AIChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { ChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import type { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
type DispatchNodeResultType
|
||||
} from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import { formatModelChars2Points } from '../../../../support/wallet/usage/utils';
|
||||
import type { SelectedDatasetType } from '@fastgpt/global/core/workflow/api.d';
|
||||
import type { SelectedDatasetType } from '@fastgpt/global/core/workflow/type/io';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { getEmbeddingModel, getRerankModel } from '../../../ai/model';
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
||||
import type {
|
||||
AIChatItemValueItemType,
|
||||
ChatHistoryItemResType,
|
||||
NodeOutputItemType,
|
||||
ToolRunResponseItemType
|
||||
} from '@fastgpt/global/core/chat/type.d';
|
||||
import type { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '@fastgpt/global/core/workflow/node/constant';
|
||||
import {
|
||||
DispatchNodeResponseKeyEnum,
|
||||
SseResponseEventEnum
|
||||
} from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type {
|
||||
ChatDispatchProps,
|
||||
DispatchNodeResultType,
|
||||
@@ -11,71 +23,58 @@ import type {
|
||||
SystemVariablesType
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import type {
|
||||
AIChatItemValueItemType,
|
||||
ChatHistoryItemResType,
|
||||
NodeOutputItemType,
|
||||
ToolRunResponseItemType
|
||||
} from '@fastgpt/global/core/chat/type.d';
|
||||
import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
||||
|
||||
import { dispatchWorkflowStart } from './init/workflowStart';
|
||||
import { dispatchChatCompletion } from './chat/oneapi';
|
||||
import { dispatchDatasetSearch } from './dataset/search';
|
||||
import { dispatchDatasetConcat } from './dataset/concat';
|
||||
import { dispatchAnswer } from './tools/answer';
|
||||
import { dispatchClassifyQuestion } from './agent/classifyQuestion';
|
||||
import { dispatchContentExtract } from './agent/extract';
|
||||
import { dispatchHttp468Request } from './tools/http468';
|
||||
import { dispatchAppRequest } from './abandoned/runApp';
|
||||
import { dispatchQueryExtension } from './tools/queryExternsion';
|
||||
import { dispatchRunPlugin } from './plugin/run';
|
||||
import { dispatchPluginInput } from './plugin/runInput';
|
||||
import { dispatchPluginOutput } from './plugin/runOutput';
|
||||
import { formatHttpError, removeSystemVariable, rewriteRuntimeWorkFlow } from './utils';
|
||||
import { valueTypeFormat } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import {
|
||||
filterWorkflowEdges,
|
||||
checkNodeRunStatus,
|
||||
textAdaptGptResponse,
|
||||
replaceEditorVariable
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import type { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import { dispatchRunTools } from './agent/runTool/index';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import type { DispatchFlowResponse } from './type';
|
||||
import { dispatchStopToolCall } from './agent/runTool/stopTool';
|
||||
import { dispatchLafRequest } from './tools/runLaf';
|
||||
import { dispatchIfElse } from './tools/runIfElse';
|
||||
import { filterPublicNodeResponseData } from '@fastgpt/global/core/chat/utils';
|
||||
import {
|
||||
checkNodeRunStatus,
|
||||
filterWorkflowEdges,
|
||||
getReferenceVariableValue,
|
||||
replaceEditorVariable,
|
||||
textAdaptGptResponse,
|
||||
valueTypeFormat
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import type {
|
||||
InteractiveNodeResponseType,
|
||||
WorkflowInteractiveResponseType
|
||||
} from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
import type { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { dispatchSystemConfig } from './init/systemConfig';
|
||||
import { dispatchUpdateVariable } from './tools/runUpdateVar';
|
||||
import type { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import { addLog } from '../../../common/system/log';
|
||||
import { surrenderProcess } from '../../../common/system/tools';
|
||||
import { dispatchAppRequest } from './abandoned/runApp';
|
||||
import { dispatchClassifyQuestion } from './ai/classifyQuestion';
|
||||
import { dispatchContentExtract } from './ai/extract';
|
||||
import { dispatchRunTools } from './ai/agent/index';
|
||||
import { dispatchStopToolCall } from './ai/agent/stopTool';
|
||||
import { dispatchToolParams } from './ai/agent/toolParams';
|
||||
import { dispatchChatCompletion } from './ai/chat';
|
||||
import { dispatchRunCode } from './code/run';
|
||||
import { dispatchTextEditor } from './tools/textEditor';
|
||||
import { dispatchCustomFeedback } from './tools/customFeedback';
|
||||
import { dispatchReadFiles } from './tools/readFiles';
|
||||
import { dispatchDatasetConcat } from './dataset/concat';
|
||||
import { dispatchDatasetSearch } from './dataset/search';
|
||||
import { dispatchSystemConfig } from './init/systemConfig';
|
||||
import { dispatchWorkflowStart } from './init/workflowStart';
|
||||
import { dispatchFormInput } from './interactive/formInput';
|
||||
import { dispatchUserSelect } from './interactive/userSelect';
|
||||
import type {
|
||||
WorkflowInteractiveResponseType,
|
||||
InteractiveNodeResponseType
|
||||
} from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
import { dispatchRunAppNode } from './plugin/runApp';
|
||||
import { dispatchLoop } from './loop/runLoop';
|
||||
import { dispatchLoopEnd } from './loop/runLoopEnd';
|
||||
import { dispatchLoopStart } from './loop/runLoopStart';
|
||||
import { dispatchFormInput } from './interactive/formInput';
|
||||
import { dispatchToolParams } from './agent/runTool/toolParams';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { filterPublicNodeResponseData } from '@fastgpt/global/core/chat/utils';
|
||||
import { dispatchRunPlugin } from './plugin/run';
|
||||
import { dispatchRunAppNode } from './plugin/runApp';
|
||||
import { dispatchPluginInput } from './plugin/runInput';
|
||||
import { dispatchPluginOutput } from './plugin/runOutput';
|
||||
import { dispatchRunTool } from './plugin/runTool';
|
||||
import { dispatchAnswer } from './tools/answer';
|
||||
import { dispatchCustomFeedback } from './tools/customFeedback';
|
||||
import { dispatchHttp468Request } from './tools/http468';
|
||||
import { dispatchQueryExtension } from './tools/queryExternsion';
|
||||
import { dispatchReadFiles } from './tools/readFiles';
|
||||
import { dispatchIfElse } from './tools/runIfElse';
|
||||
import { dispatchLafRequest } from './tools/runLaf';
|
||||
import { dispatchUpdateVariable } from './tools/runUpdateVar';
|
||||
import { dispatchTextEditor } from './tools/textEditor';
|
||||
import type { DispatchFlowResponse } from './type';
|
||||
import { formatHttpError, removeSystemVariable, rewriteRuntimeWorkFlow } from './utils';
|
||||
|
||||
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||
@@ -91,7 +90,7 @@ const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.pluginInput]: dispatchPluginInput,
|
||||
[FlowNodeTypeEnum.pluginOutput]: dispatchPluginOutput,
|
||||
[FlowNodeTypeEnum.queryExtension]: dispatchQueryExtension,
|
||||
[FlowNodeTypeEnum.tools]: dispatchRunTools,
|
||||
[FlowNodeTypeEnum.agent]: dispatchRunTools,
|
||||
[FlowNodeTypeEnum.stopTool]: dispatchStopToolCall,
|
||||
[FlowNodeTypeEnum.toolParams]: dispatchToolParams,
|
||||
[FlowNodeTypeEnum.lafModule]: dispatchLafRequest,
|
||||
@@ -116,7 +115,8 @@ const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.comment]: () => Promise.resolve(),
|
||||
[FlowNodeTypeEnum.toolSet]: () => Promise.resolve(),
|
||||
|
||||
[FlowNodeTypeEnum.runApp]: dispatchAppRequest // abandoned
|
||||
// @deprecated
|
||||
[FlowNodeTypeEnum.runApp]: dispatchAppRequest
|
||||
};
|
||||
|
||||
type Props = ChatDispatchProps & {
|
||||
@@ -460,7 +460,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
|
||||
if (!nodeRunResult) return [];
|
||||
|
||||
/*
|
||||
/*
|
||||
特殊情况:
|
||||
通过 skipEdges 可以判断是运行了分支节点。
|
||||
由于分支节点,可能会实现递归调用(skip 连线往前递归)
|
||||
@@ -729,7 +729,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
if (
|
||||
item.flowNodeType !== FlowNodeTypeEnum.userSelect &&
|
||||
item.flowNodeType !== FlowNodeTypeEnum.formInput &&
|
||||
item.flowNodeType !== FlowNodeTypeEnum.tools
|
||||
item.flowNodeType !== FlowNodeTypeEnum.agent
|
||||
) {
|
||||
item.isEntry = false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { dispatchWorkFlow } from '../index';
|
||||
import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils';
|
||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { getChildAppRuntimeById } from '../../../app/plugin/controller';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import {
|
||||
getWorkflowEntryNodeIds,
|
||||
storeEdges2RuntimeEdges,
|
||||
@@ -13,11 +14,12 @@ 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';
|
||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils';
|
||||
import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils';
|
||||
import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { getChildAppRuntimeById, splitCombinePluginId } from '../../../app/plugin/controller';
|
||||
import { dispatchWorkFlow } from '../index';
|
||||
import { getUserChatInfoAndAuthTeamPoints } from '../../../../support/permission/auth/team';
|
||||
import { dispatchRunTool } from './runTool';
|
||||
|
||||
type RunPluginProps = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.forbidStream]?: boolean;
|
||||
@@ -35,6 +37,26 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
||||
return Promise.reject('pluginId can not find');
|
||||
}
|
||||
|
||||
// Adapt <= 4.10 system tool
|
||||
const { source, pluginId: formatPluginId } = splitCombinePluginId(pluginId);
|
||||
if (source === PluginSourceEnum.systemTool) {
|
||||
return dispatchRunTool({
|
||||
...props,
|
||||
node: {
|
||||
...props.node,
|
||||
toolConfig: {
|
||||
systemTool: {
|
||||
toolId: formatPluginId
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
1. Team app
|
||||
2. Admin selected system tool
|
||||
*/
|
||||
const { files } = chatValue2RuntimePrompt(query);
|
||||
|
||||
// auth plugin
|
||||
|
||||
@@ -1,51 +1,146 @@
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import {
|
||||
type DispatchNodeResultType,
|
||||
type ModuleDispatchProps
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { MCPClient } from '../../../app/mcp';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { getSecretValue } from '../../../../common/secret/utils';
|
||||
import type { McpToolDataType } from '@fastgpt/global/core/app/mcpTools/type';
|
||||
import { runTool } from '../../../app/tool/api';
|
||||
import { MongoSystemPlugin } from '../../../app/plugin/systemPluginSchema';
|
||||
import { SystemToolInputTypeEnum } from '@fastgpt/global/core/app/systemTool/constants';
|
||||
import type { StoreSecretValueType } from '@fastgpt/global/common/secret/type';
|
||||
import { getSystemPluginById, splitCombinePluginId } from '../../../app/plugin/controller';
|
||||
|
||||
type RunToolProps = ModuleDispatchProps<{
|
||||
toolData?: McpToolDataType;
|
||||
[NodeInputKeyEnum.toolData]: McpToolDataType;
|
||||
}>;
|
||||
type SystemInputConfigType = {
|
||||
type: SystemToolInputTypeEnum;
|
||||
value: StoreSecretValueType;
|
||||
};
|
||||
|
||||
type RunToolResponse = DispatchNodeResultType<{
|
||||
[NodeOutputKeyEnum.rawResponse]?: any;
|
||||
}>;
|
||||
type RunToolProps = ModuleDispatchProps<
|
||||
{
|
||||
[NodeInputKeyEnum.toolData]?: McpToolDataType;
|
||||
[NodeInputKeyEnum.systemInputConfig]?: SystemInputConfigType;
|
||||
} & Record<string, any>
|
||||
>;
|
||||
|
||||
type RunToolResponse = DispatchNodeResultType<
|
||||
{
|
||||
[NodeOutputKeyEnum.rawResponse]?: any;
|
||||
} & Record<string, any>
|
||||
>;
|
||||
|
||||
export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolResponse> => {
|
||||
const {
|
||||
params,
|
||||
node: { avatar }
|
||||
runningUserInfo,
|
||||
runningAppInfo,
|
||||
variables,
|
||||
node: { name, avatar, toolConfig, version }
|
||||
} = props;
|
||||
|
||||
const { toolData, system_toolData, ...restParams } = params;
|
||||
const { name: toolName, url, headerSecret } = toolData || system_toolData;
|
||||
|
||||
const mcpClient = new MCPClient({
|
||||
url,
|
||||
headers: getSecretValue({
|
||||
storeSecret: headerSecret
|
||||
})
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await mcpClient.toolCall(toolName, restParams);
|
||||
// run system tool
|
||||
if (toolConfig?.systemTool?.toolId) {
|
||||
const tool = await getSystemPluginById(toolConfig.systemTool!.toolId);
|
||||
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
toolRes: result,
|
||||
moduleLogo: avatar
|
||||
},
|
||||
[DispatchNodeResponseKeyEnum.toolResponses]: result,
|
||||
[NodeOutputKeyEnum.rawResponse]: result
|
||||
};
|
||||
const inputConfigParams = await (async () => {
|
||||
switch (params.system_input_config?.type) {
|
||||
case SystemToolInputTypeEnum.team:
|
||||
return Promise.reject(new Error('This is not supported yet'));
|
||||
case SystemToolInputTypeEnum.manual:
|
||||
const val = params.system_input_config.value || {};
|
||||
return getSecretValue({
|
||||
storeSecret: val
|
||||
});
|
||||
case SystemToolInputTypeEnum.system:
|
||||
default:
|
||||
// read from mongo
|
||||
const dbPlugin = await MongoSystemPlugin.findOne({
|
||||
pluginId: toolConfig.systemTool?.toolId
|
||||
}).lean();
|
||||
return dbPlugin?.inputListVal || {};
|
||||
}
|
||||
})();
|
||||
const inputs = {
|
||||
...Object.fromEntries(
|
||||
Object.entries(params).filter(([key]) => key !== NodeInputKeyEnum.systemInputConfig)
|
||||
),
|
||||
...inputConfigParams
|
||||
};
|
||||
|
||||
const formatToolId = tool.id.split('-')[1];
|
||||
const result = await runTool({
|
||||
toolId: formatToolId,
|
||||
inputs,
|
||||
systemVar: {
|
||||
user: {
|
||||
id: variables.userId,
|
||||
teamId: runningUserInfo.teamId,
|
||||
name: runningUserInfo.tmbId
|
||||
},
|
||||
app: {
|
||||
id: runningAppInfo.id,
|
||||
name: runningAppInfo.id
|
||||
},
|
||||
tool: {
|
||||
id: formatToolId,
|
||||
version
|
||||
},
|
||||
time: variables.cTime
|
||||
}
|
||||
});
|
||||
|
||||
const usagePoints = await (async () => {
|
||||
if (
|
||||
params.system_input_config?.type !== SystemToolInputTypeEnum.system ||
|
||||
result[NodeOutputKeyEnum.systemError]
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
return tool.currentCost ?? 0;
|
||||
})();
|
||||
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
toolRes: result,
|
||||
moduleLogo: avatar,
|
||||
totalPoints: usagePoints
|
||||
},
|
||||
[DispatchNodeResponseKeyEnum.toolResponses]: result,
|
||||
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
|
||||
{
|
||||
moduleName: name,
|
||||
totalPoints: usagePoints
|
||||
}
|
||||
],
|
||||
...result
|
||||
};
|
||||
} else {
|
||||
// mcp tool
|
||||
const { toolData, system_toolData, ...restParams } = params;
|
||||
const { name: toolName, url, headerSecret } = toolData || system_toolData;
|
||||
|
||||
const mcpClient = new MCPClient({
|
||||
url,
|
||||
headers: getSecretValue({
|
||||
storeSecret: headerSecret
|
||||
})
|
||||
});
|
||||
const result = await mcpClient.toolCall(toolName, restParams);
|
||||
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
toolRes: result,
|
||||
moduleLogo: avatar
|
||||
},
|
||||
[DispatchNodeResponseKeyEnum.toolResponses]: result,
|
||||
[NodeOutputKeyEnum.rawResponse]: result
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import {
|
||||
ContentTypes,
|
||||
NodeInputKeyEnum,
|
||||
NodeOutputKeyEnum,
|
||||
VARIABLE_NODE_ID,
|
||||
@@ -10,27 +11,22 @@ import {
|
||||
SseResponseEventEnum
|
||||
} from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import axios from 'axios';
|
||||
import { formatHttpError } from '../utils';
|
||||
import { valueTypeFormat } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { SERVICE_LOCAL_HOST } from '../../../../common/system/tools';
|
||||
import { addLog } from '../../../../common/system/log';
|
||||
import { type DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import {
|
||||
textAdaptGptResponse,
|
||||
replaceEditorVariable,
|
||||
formatVariableValByType,
|
||||
getReferenceVariableValue
|
||||
getReferenceVariableValue,
|
||||
replaceEditorVariable,
|
||||
textAdaptGptResponse
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { ContentTypes } from '@fastgpt/global/core/workflow/constants';
|
||||
import { uploadFileFromBase64Img } from '../../../../common/file/gridfs/controller';
|
||||
import { ReadFileBaseUrl } from '@fastgpt/global/common/file/constants';
|
||||
import { createFileToken } from '../../../../support/permission/controller';
|
||||
import { JSONPath } from 'jsonpath-plus';
|
||||
import type { SystemPluginSpecialResponse } from '../../../../../plugins/type';
|
||||
import json5 from 'json5';
|
||||
import { JSONPath } from 'jsonpath-plus';
|
||||
import { getSecretValue } from '../../../../common/secret/utils';
|
||||
import type { StoreSecretValueType } from '@fastgpt/global/common/secret/type';
|
||||
import { addLog } from '../../../../common/system/log';
|
||||
import { SERVICE_LOCAL_HOST } from '../../../../common/system/tools';
|
||||
import { formatHttpError } from '../utils';
|
||||
|
||||
type PropsArrType = {
|
||||
key: string;
|
||||
@@ -302,19 +298,6 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
|
||||
try {
|
||||
const { formatResponse, rawResponse } = await (async () => {
|
||||
const systemPluginCb = global.systemPluginCb;
|
||||
if (systemPluginCb[httpReqUrl]) {
|
||||
const pluginResult = await replaceSystemPluginResponse({
|
||||
response: await systemPluginCb[httpReqUrl](requestBody),
|
||||
teamId,
|
||||
tmbId
|
||||
});
|
||||
|
||||
return {
|
||||
formatResponse: pluginResult,
|
||||
rawResponse: pluginResult
|
||||
};
|
||||
}
|
||||
return fetchData({
|
||||
method: httpMethod,
|
||||
url: httpReqUrl,
|
||||
@@ -426,38 +409,3 @@ async function fetchData({
|
||||
rawResponse: response
|
||||
};
|
||||
}
|
||||
|
||||
// Replace some special response from system plugin
|
||||
async function replaceSystemPluginResponse({
|
||||
response,
|
||||
teamId,
|
||||
tmbId
|
||||
}: {
|
||||
response: Record<string, any>;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
}) {
|
||||
for await (const key of Object.keys(response)) {
|
||||
if (typeof response[key] === 'object' && response[key].type === 'SYSTEM_PLUGIN_BASE64') {
|
||||
const fileObj = response[key] as SystemPluginSpecialResponse;
|
||||
const filename = `${tmbId}-${Date.now()}.${fileObj.extension}`;
|
||||
try {
|
||||
const fileId = await uploadFileFromBase64Img({
|
||||
teamId,
|
||||
tmbId,
|
||||
bucketName: 'chat',
|
||||
base64: fileObj.value,
|
||||
filename,
|
||||
metadata: {}
|
||||
});
|
||||
response[key] = `${ReadFileBaseUrl}/${filename}?token=${await createFileToken({
|
||||
bucketName: 'chat',
|
||||
teamId,
|
||||
uid: tmbId,
|
||||
fileId
|
||||
})}`;
|
||||
} catch (error) {}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user