fix: toolset rewrite

This commit is contained in:
archer
2025-09-08 17:43:03 +08:00
parent 721787b3ad
commit 7bd725d2c8
2 changed files with 113 additions and 107 deletions

View File

@@ -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<RuntimeNodeItemType>((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<RuntimeNodeItemType>((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 中。

View File

@@ -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[]> => {
}): 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<ChatCompletionTool>((item) => {
const toolParams: FlowNodeInputItemType[] = [];
let jsonSchema: JSONSchemaInputType | undefined;
const nodeTools = subApps.map<ChatCompletionTool>((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<string, any> = {};
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<string, any> = {};
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];
};