From 7bd725d2c8ec245b2edf31238a5374185e0003f1 Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Mon, 8 Sep 2025 17:43:03 +0800 Subject: [PATCH] fix: toolset rewrite --- .../core/workflow/dispatch/ai/agent/index.ts | 44 +++-- .../workflow/dispatch/ai/agent/sub/index.ts | 176 +++++++++--------- 2 files changed, 113 insertions(+), 107 deletions(-) diff --git a/packages/service/core/workflow/dispatch/ai/agent/index.ts b/packages/service/core/workflow/dispatch/ai/agent/index.ts index 5ea8bf1f4..3d8bdbe73 100644 --- a/packages/service/core/workflow/dispatch/ai/agent/index.ts +++ b/packages/service/core/workflow/dispatch/ai/agent/index.ts @@ -65,7 +65,7 @@ import type { SystemToolInputTypeEnum } from '@fastgpt/global/core/app/systemToo import type { StoreSecretValueType } from '@fastgpt/global/common/secret/type'; import type { appConfigType } from './sub/app'; import type { DatasetConfigType } from './sub/dataset'; -import { getSubApps } from './sub'; +import { getSubApps, rewriteSubAppsToolset } from './sub'; import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; import { dispatchRunTool } from '../../child/runTool'; import { dispatchRunAppNode } from '../../child/runApp'; @@ -123,23 +123,26 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise } } = props; - const runtimeSubApps = subApps.map((node) => { - return { - nodeId: node.id, - name: node.name, - avatar: node.avatar, - intro: node.intro, - toolDescription: node.toolDescription, - flowNodeType: node.flowNodeType, - showStatus: node.showStatus, - isEntry: false, - inputs: node.inputs, - outputs: node.outputs, - pluginId: node.pluginId, - version: node.version, - toolConfig: node.toolConfig, - catchError: node.catchError - }; + const runtimeSubApps = await rewriteSubAppsToolset({ + subApps: subApps.map((node) => { + return { + nodeId: node.id, + name: node.name, + avatar: node.avatar, + intro: node.intro, + toolDescription: node.toolDescription, + flowNodeType: node.flowNodeType, + showStatus: node.showStatus, + isEntry: false, + inputs: node.inputs, + outputs: node.outputs, + pluginId: node.pluginId, + version: node.version, + toolConfig: node.toolConfig, + catchError: node.catchError + }; + }), + lang }); try { @@ -151,6 +154,9 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise fileLinks = undefined; } + const subAppList = getSubApps({ subApps: runtimeSubApps, urls: fileLinks }); + console.log(JSON.stringify(subAppList, null, 2)); + // Init tool params const toolNodesMap = new Map(runtimeSubApps.map((item) => [item.nodeId, item])); const getToolInfo = (id: string) => { @@ -161,8 +167,6 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise }; }; - const subAppList = await getSubApps({ subApps: runtimeSubApps, urls: fileLinks, lang }); - console.log(JSON.stringify(subAppList, null, 2)); // const combinedSystemPrompt = `${parseAgentSystem({ systemPrompt, toolNodesMap })}\n\n${getTopAgentConstantPrompt()}`; // TODO: 把 files 加入 query 中。 diff --git a/packages/service/core/workflow/dispatch/ai/agent/sub/index.ts b/packages/service/core/workflow/dispatch/ai/agent/sub/index.ts index 57f9921c2..059831753 100644 --- a/packages/service/core/workflow/dispatch/ai/agent/sub/index.ts +++ b/packages/service/core/workflow/dispatch/ai/agent/sub/index.ts @@ -18,15 +18,59 @@ import { getMCPChildren } from '../../../../../app/mcp'; import { getMCPToolRuntimeNode } from '@fastgpt/global/core/app/mcpTools/utils'; import type { localeType } from '@fastgpt/global/common/i18n/type'; -export const getSubApps = async ({ +export const rewriteSubAppsToolset = ({ subApps, - lang, - urls + lang }: { subApps: RuntimeNodeItemType[]; lang?: localeType; +}) => { + return Promise.all( + subApps.map(async (node) => { + if (node.flowNodeType === FlowNodeTypeEnum.toolSet) { + const systemToolId = node.toolConfig?.systemToolSet?.toolId; + const mcpToolsetVal = node.toolConfig?.mcpToolSet ?? node.inputs[0].value; + if (systemToolId) { + const children = await getSystemToolRunTimeNodeFromSystemToolset({ + toolSetNode: node, + lang + }); + return children; + } else if (mcpToolsetVal) { + const app = await MongoApp.findOne({ _id: node.pluginId }).lean(); + if (!app) return []; + const toolList = await getMCPChildren(app); + + const parentId = mcpToolsetVal.toolId ?? node.pluginId; + const children = toolList.map((tool, index) => { + const newToolNode = getMCPToolRuntimeNode({ + avatar: node.avatar, + tool, + // New ?? Old + parentId + }); + newToolNode.nodeId = `${parentId}${index}`; // ID 不能随机,否则下次生成时候就和之前的记录对不上 + newToolNode.name = `${node.name}/${tool.name}`; + + return newToolNode; + }); + + return children; + } + return []; + } else { + return [node]; + } + }) + ).then((res) => res.flat()); +}; +export const getSubApps = ({ + subApps, + urls +}: { + subApps: RuntimeNodeItemType[]; urls?: string[]; -}): Promise => { +}): ChatCompletionTool[] => { // System Tools: Plan Agent, stop sign, model agent. const systemTools: ChatCompletionTool[] = [ PlanAgentTool, @@ -36,105 +80,63 @@ export const getSubApps = async ({ ]; // Node Tools - const getToolNode = (nodes: RuntimeNodeItemType[]) => { - return nodes.map((item) => { - const toolParams: FlowNodeInputItemType[] = []; - let jsonSchema: JSONSchemaInputType | undefined; + const nodeTools = subApps.map((item) => { + const toolParams: FlowNodeInputItemType[] = []; + let jsonSchema: JSONSchemaInputType | undefined; - for (const input of item.inputs) { - if (input.toolDescription) { - toolParams.push(input); - } - - if (input.key === NodeInputKeyEnum.toolData) { - jsonSchema = (input.value as McpToolDataType).inputSchema; - } + for (const input of item.inputs) { + if (input.toolDescription) { + toolParams.push(input); } - const description = JSON.stringify({ - type: item.flowNodeType, - name: item.name, - intro: item.toolDescription || item.intro - }); - - if (jsonSchema) { - return { - type: 'function', - function: { - name: item.nodeId, - description, - parameters: jsonSchema - } - }; + if (input.key === NodeInputKeyEnum.toolData) { + jsonSchema = (input.value as McpToolDataType).inputSchema; } + } - const properties: Record = {}; - toolParams.forEach((param) => { - const jsonSchema = param.valueType - ? valueTypeJsonSchemaMap[param.valueType] || toolValueTypeList[0].jsonSchema - : toolValueTypeList[0].jsonSchema; - - properties[param.key] = { - ...jsonSchema, - description: param.toolDescription || '', - enum: param.enum?.split('\n').filter(Boolean) || undefined - }; - }); + const description = JSON.stringify({ + type: item.flowNodeType, + name: item.name, + intro: item.toolDescription || item.intro + }); + if (jsonSchema) { return { type: 'function', function: { name: item.nodeId, description, - parameters: { - type: 'object', - properties, - required: toolParams.filter((param) => param.required).map((param) => param.key) - } + parameters: jsonSchema } }; + } + + const properties: Record = {}; + toolParams.forEach((param) => { + const jsonSchema = param.valueType + ? valueTypeJsonSchemaMap[param.valueType] || toolValueTypeList[0].jsonSchema + : toolValueTypeList[0].jsonSchema; + + properties[param.key] = { + ...jsonSchema, + description: param.toolDescription || '', + enum: param.enum?.split('\n').filter(Boolean) || undefined + }; }); - }; - const nodeTools = ( - await Promise.all( - subApps.map(async (node) => { - if (node.flowNodeType === FlowNodeTypeEnum.toolSet) { - const systemToolId = node.toolConfig?.systemToolSet?.toolId; - const mcpToolsetVal = node.toolConfig?.mcpToolSet ?? node.inputs[0].value; - if (systemToolId) { - const children = await getSystemToolRunTimeNodeFromSystemToolset({ - toolSetNode: node, - lang - }); - return getToolNode(children); - } else if (mcpToolsetVal) { - const app = await MongoApp.findOne({ _id: node.pluginId }).lean(); - if (!app) return []; - const toolList = await getMCPChildren(app); - const parentId = mcpToolsetVal.toolId ?? node.pluginId; - const children = toolList.map((tool, index) => { - const newToolNode = getMCPToolRuntimeNode({ - avatar: node.avatar, - tool, - // New ?? Old - parentId - }); - newToolNode.nodeId = `${parentId}${index}`; // ID 不能随机,否则下次生成时候就和之前的记录对不上 - newToolNode.name = `${node.name}/${tool.name}`; - - return newToolNode; - }); - - return getToolNode(children); - } - return []; - } else { - return getToolNode([node]); + return { + type: 'function', + function: { + name: item.nodeId, + description, + parameters: { + type: 'object', + properties, + required: toolParams.filter((param) => param.required).map((param) => param.key) } - }) - ) - ).flat(); + } + }; + }); return [...systemTools, ...nodeTools]; };