From b13a4a62ec7f8c419a4a12f078fbb4514e1a1e77 Mon Sep 17 00:00:00 2001 From: FinleyGe Date: Mon, 17 Nov 2025 16:31:11 +0800 Subject: [PATCH 1/4] feat: generate unique version string --- lib/worker/loadTool.ts | 42 +++++++++++++++++++-------- modules/tool/build/build-json.ts | 42 +++++++++++++++++++-------- modules/tool/loadToolDev.ts | 42 +++++++++++++++++++-------- modules/tool/parseMod.ts | 32 +++++++++++--------- modules/tool/type/tool.ts | 1 + modules/tool/utils/tool.ts | 50 ++++++++++++++++++++------------ 6 files changed, 142 insertions(+), 67 deletions(-) diff --git a/lib/worker/loadTool.ts b/lib/worker/loadTool.ts index 57c1c66d..e52a79e2 100644 --- a/lib/worker/loadTool.ts +++ b/lib/worker/loadTool.ts @@ -8,6 +8,7 @@ import { ToolTagEnum } from '@tool/type/tags'; import { existsSync } from 'fs'; import { readdir } from 'fs/promises'; import { join } from 'path'; +import { generateToolVersion, generateToolSetVersion } from '@tool/utils/tool'; const LoadToolsDev = async (filename: string): Promise => { if (isProd) { @@ -28,16 +29,6 @@ const LoadToolsDev = async (filename: string): Promise => { const parentIcon = rootMod.icon ?? getIconPath(`${toolsetId}/logo`); if (isToolSet) { - tools.push({ - ...rootMod, - tags: rootMod.tags || [ToolTagEnum.enum.other], - toolId: toolsetId, - icon: parentIcon, - toolFilename: filename, - cb: () => Promise.resolve({}), - versionList: [] - }); - const children: ToolType[] = []; { @@ -49,27 +40,54 @@ const LoadToolsDev = async (filename: string): Promise => { const toolId = childMod.toolId || `${toolsetId}/${file}`; const childIcon = childMod.icon ?? rootMod.icon ?? getIconPath(`${toolsetId}/${file}/logo`); + + // Generate version for child tool + const childVersion = childMod.versionList + ? generateToolVersion(childMod.versionList) + : generateToolVersion([]); + children.push({ ...childMod, toolId, toolFilename: filename, icon: childIcon, - parentId: toolsetId + parentId: toolsetId, + version: childVersion }); } } + // Generate version for tool set based on children + const toolSetVersion = generateToolSetVersion(children); + + tools.push({ + ...rootMod, + tags: rootMod.tags || [ToolTagEnum.enum.other], + toolId: toolsetId, + icon: parentIcon, + toolFilename: filename, + cb: () => Promise.resolve({}), + versionList: [], + version: toolSetVersion + }); + tools.push(...children); } else { // is not toolset const icon = rootMod.icon ?? getIconPath(`${toolsetId}/logo`); + // Generate version for single tool + const toolVersion = (rootMod as any).versionList + ? generateToolVersion((rootMod as any).versionList) + : generateToolVersion([]); + tools.push({ ...(rootMod as ToolType), tags: rootMod.tags || [ToolTagEnum.enum.other], toolId: toolsetId, icon, - toolFilename: filename + toolFilename: filename, + version: toolVersion }); } diff --git a/modules/tool/build/build-json.ts b/modules/tool/build/build-json.ts index 9a1f930e..f7c726e1 100644 --- a/modules/tool/build/build-json.ts +++ b/modules/tool/build/build-json.ts @@ -5,6 +5,7 @@ import { existsSync, writeFileSync } from 'fs'; import { readdir } from 'fs/promises'; import { join } from 'path'; import { ToolDetailSchema } from 'sdk/client'; +import { generateToolVersion, generateToolSetVersion } from '../utils/tool'; const filterToolList = ['.DS_Store', '.git', '.github', 'node_modules', 'dist', 'scripts']; @@ -26,16 +27,6 @@ const LoadToolsDev = async (filename: string): Promise => { const parentIcon = rootMod.icon ?? `${S3BasePath}${UploadToolsS3Path}/${toolsetId}/logo`; if (isToolSet) { - tools.push({ - ...rootMod, - tags: rootMod.tags || [ToolTagEnum.enum.other], - toolId: toolsetId, - icon: parentIcon, - toolFilename: filename, - cb: () => Promise.resolve({}), - versionList: [] - }); - const children: ToolType[] = []; { @@ -50,27 +41,54 @@ const LoadToolsDev = async (filename: string): Promise => { childMod.icon ?? rootMod.icon ?? `${S3BasePath}${UploadToolsS3Path}/${toolsetId}/${file}/logo`; + + // Generate version for child tool + const childVersion = childMod.versionList + ? generateToolVersion(childMod.versionList) + : generateToolVersion([]); + children.push({ ...childMod, toolId, toolFilename: filename, icon: childIcon, - parentId: toolsetId + parentId: toolsetId, + version: childVersion }); } } + // Generate version for tool set based on children + const toolSetVersion = generateToolSetVersion(children); + + tools.push({ + ...rootMod, + tags: rootMod.tags || [ToolTagEnum.enum.other], + toolId: toolsetId, + icon: parentIcon, + toolFilename: filename, + cb: () => Promise.resolve({}), + versionList: [], + version: toolSetVersion + }); + tools.push(...children); } else { // is not toolset const icon = rootMod.icon ?? `${S3BasePath}${UploadToolsS3Path}/${toolsetId}/logo`; + // Generate version for single tool + const toolVersion = (rootMod as any).versionList + ? generateToolVersion((rootMod as any).versionList) + : generateToolVersion([]); + tools.push({ ...(rootMod as ToolType), tags: rootMod.tags || [ToolTagEnum.enum.other], toolId: toolsetId, icon, - toolFilename: filename + toolFilename: filename, + version: toolVersion }); } diff --git a/modules/tool/loadToolDev.ts b/modules/tool/loadToolDev.ts index 83b660df..62c115ee 100644 --- a/modules/tool/loadToolDev.ts +++ b/modules/tool/loadToolDev.ts @@ -9,6 +9,7 @@ import type { ToolType, ToolSetType } from './type'; import { ToolTagEnum } from './type/tags'; import { publicS3Server } from '@/s3'; import { mimeMap } from '@/s3/const'; +import { generateToolVersion, generateToolSetVersion } from './utils/tool'; /** * Load Tools in dev mode. Only avaliable in dev mode @@ -82,16 +83,6 @@ export const LoadToolsDev = async (filename: string): Promise => { (await publicS3Server.generateExternalUrl(`${UploadToolsS3Path}/${toolsetId}/logo`)); if (isToolSet) { - tools.push({ - ...rootMod, - tags: rootMod.tags || [ToolTagEnum.enum.other], - toolId: toolsetId, - icon: parentIcon, - toolFilename: filename, - cb: () => Promise.resolve({}), - versionList: [] - }); - const children: ToolType[] = []; { @@ -161,16 +152,37 @@ export const LoadToolsDev = async (filename: string): Promise => { (await publicS3Server.generateExternalUrl( `${UploadToolsS3Path}/${toolsetId}/${file}/logo` )); + + // Generate version for child tool + const childVersion = childMod.versionList + ? generateToolVersion(childMod.versionList) + : generateToolVersion([]); + children.push({ ...childMod, toolId, toolFilename: filename, icon: childIcon, - parentId: toolsetId + parentId: toolsetId, + version: childVersion }); } } + // Generate version for tool set based on children + const toolSetVersion = generateToolSetVersion(children); + + tools.push({ + ...rootMod, + tags: rootMod.tags || [ToolTagEnum.enum.other], + toolId: toolsetId, + icon: parentIcon, + toolFilename: filename, + cb: () => Promise.resolve({}), + versionList: [], + version: toolSetVersion ?? '' + }); + tools.push(...children); } else { // is not toolset @@ -178,12 +190,18 @@ export const LoadToolsDev = async (filename: string): Promise => { rootMod.icon ?? (await publicS3Server.generateExternalUrl(`${UploadToolsS3Path}/${toolsetId}/logo`)); + // Generate version for single tool + const toolVersion = (rootMod as any).versionList + ? generateToolVersion((rootMod as any).versionList) + : generateToolVersion([]); + tools.push({ ...(rootMod as ToolType), tags: rootMod.tags || [ToolTagEnum.enum.other], toolId: toolsetId, icon, - toolFilename: filename + toolFilename: filename, + version: toolVersion }); } diff --git a/modules/tool/parseMod.ts b/modules/tool/parseMod.ts index e47a8115..98c15bbd 100644 --- a/modules/tool/parseMod.ts +++ b/modules/tool/parseMod.ts @@ -2,6 +2,7 @@ import { ToolTagEnum } from 'sdk/client'; import { UploadToolsS3Path } from './constants'; import type { ToolSetType, ToolType } from './type'; import { PublicBucketBaseURL } from '@/s3/const'; +import { generateToolVersion, generateToolSetVersion } from './utils/tool'; export const getIconPath = (name: string) => `${PublicBucketBaseURL}${UploadToolsS3Path}/${name}`; @@ -21,17 +22,6 @@ export const parseMod = async ({ const parentIcon = rootMod.icon || getIconPath(`${toolsetId}/logo`); - // push parent - tools.push({ - ...rootMod, - tags: rootMod.tags || [ToolTagEnum.enum.other], - toolId: toolsetId, - icon: parentIcon, - toolFilename: `${filename}`, - cb: () => Promise.resolve({}), - versionList: [] - }); - const children = rootMod.children; for (const child of children) { @@ -39,6 +29,8 @@ export const parseMod = async ({ const childIcon = child.icon || rootMod.icon || getIconPath(`${childToolId}/logo`); + // Generate version for child tool + const childVersion = child.version ?? ''; tools.push({ ...child, toolId: childToolId, @@ -47,9 +39,22 @@ export const parseMod = async ({ courseUrl: rootMod.courseUrl, author: rootMod.author, icon: childIcon, - toolFilename: filename + toolFilename: filename, + version: childVersion }); } + + // push parent + tools.push({ + ...rootMod, + tags: rootMod.tags || [ToolTagEnum.enum.other], + toolId: toolsetId, + icon: parentIcon, + toolFilename: `${filename}`, + cb: () => Promise.resolve({}), + versionList: [], + version: generateToolSetVersion(children) || '' + }); } else { // is not toolset const toolId = rootMod.toolId; @@ -61,7 +66,8 @@ export const parseMod = async ({ tags: rootMod.tags || [ToolTagEnum.enum.tools], icon, toolId, - toolFilename: filename + toolFilename: filename, + version: rootMod.version ?? '' }); } return tools; diff --git a/modules/tool/type/tool.ts b/modules/tool/type/tool.ts index afc3c729..5cda6395 100644 --- a/modules/tool/type/tool.ts +++ b/modules/tool/type/tool.ts @@ -51,6 +51,7 @@ export const ToolSchema = ToolConfigWithCbSchema.extend({ parentId: z.string().optional().describe('The parent id of the tool'), toolFilename: z.string(), + version: z.string().describe('The version hash of the tool'), // ToolSet Parent secretInputConfig: z .array(InputConfigSchema) diff --git a/modules/tool/utils/tool.ts b/modules/tool/utils/tool.ts index 1534d84e..d7ca3314 100644 --- a/modules/tool/utils/tool.ts +++ b/modules/tool/utils/tool.ts @@ -1,7 +1,8 @@ import type { z } from 'zod'; -import type { ToolSetConfigType } from '@tool/type'; +import type { ToolSetConfigType, ToolType, ToolSetType } from '@tool/type'; import { ToolConfigSchema } from '@tool/type/tool'; import type { RunToolSecondParamsType } from '@tool/type/req'; +import { createHash } from 'node:crypto'; export const exportTool = ({ toolCb, @@ -46,20 +47,33 @@ export const exportToolSet = ({ config }: { config: ToolSetConfigType }) => { }; }; -// export function formatToolList( -// list: (z.infer | z.infer)[] -// ): ToolListItemType[] { -// return list.map((item) => ({ -// author: item.author, -// name: item.name, -// parentId: 'parentId' in item ? item.parentId : undefined, -// courseUrl: item.courseUrl, -// id: item.toolId, -// avatar: item.icon, -// versionList: item.versionList, -// description: item.description, -// toolDescription: item.toolDescription, -// templateType: item.tags?.[0], -// secretInputConfig: item.secretInputConfig -// })); -// } +/** + * Generate version hash for a single tool based on versionList + * @param versionList - Array of version objects with value field + * @returns First 8 characters of SHA256 hash of concatenated version values + */ +export function generateToolVersion( + versionList: Array<{ value: string; description?: string; inputs: any[]; outputs: any[] }> +): string { + const versionString = versionList.map((v) => v.value).join(''); + return createHash('sha256').update(versionString).digest('hex').substring(0, 8); +} + +/** + * Generate version hash for a tool set based on all child tools' versions + * @param children - Array of child tools + * @returns First 8 characters of SHA256 hash of all child version hashes concatenated + */ +export function generateToolSetVersion(children: ToolType[]) { + if (!children || children.length === 0) { + return undefined; + } + + const childVersions = children.map((child) => child.version || '').sort(); + const versionString = childVersions.join(''); + if (versionString.length === 0) { + return undefined; + } + + return createHash('sha256').update(versionString).digest('hex').substring(0, 8); +} From 3c77bef8167bb35b471c8222b46c6dc1d786bf9c Mon Sep 17 00:00:00 2001 From: FinleyGe Date: Wed, 19 Nov 2025 11:10:04 +0800 Subject: [PATCH 2/4] fix: refresh tool --- modules/tool/init.ts | 4 ++-- runtime/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/tool/init.ts b/modules/tool/init.ts index 556bc7ad..5fe6aded 100644 --- a/modules/tool/init.ts +++ b/modules/tool/init.ts @@ -82,11 +82,11 @@ export async function initTools() { } addLog.info(`Load Tools: ${toolMap.size}`); - isIniting = false; + global.isIniting = false; return toolMap; } catch (e) { addLog.error(`Init Tools Error:`, e); - isIniting = false; + global.isIniting = false; return getCachedData(SystemCacheKeyEnum.systemTool); } } diff --git a/runtime/index.ts b/runtime/index.ts index a51cbff6..3445cbd2 100644 --- a/runtime/index.ts +++ b/runtime/index.ts @@ -1,4 +1,4 @@ -import { getCachedData } from '@/cache'; +import { refreshVersionKey } from '@/cache'; import { SystemCacheKeyEnum } from '@/cache/type'; import { isProd } from '@/constants'; import { initOpenAPI } from '@/contract/openapi'; @@ -51,7 +51,7 @@ async function main(reboot: boolean = false) { await ensureDir(tempToolsDir); // ensure the unpkged tools temp dir await Promise.all([ - getCachedData(SystemCacheKeyEnum.systemTool), // init system tool + refreshVersionKey(SystemCacheKeyEnum.systemTool), // init system tool initModels(reboot), initWorkflowTemplates() ]); From 52226a964dda4caf6f72f7735964fda83dae7378 Mon Sep 17 00:00:00 2001 From: FinleyGe Date: Wed, 19 Nov 2025 12:37:33 +0800 Subject: [PATCH 3/4] chore: bump sdk version --- lib/worker/loadTool.ts | 2 +- modules/tool/build/build-json.ts | 2 +- sdk/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/worker/loadTool.ts b/lib/worker/loadTool.ts index e52a79e2..b15aebff 100644 --- a/lib/worker/loadTool.ts +++ b/lib/worker/loadTool.ts @@ -58,7 +58,7 @@ const LoadToolsDev = async (filename: string): Promise => { } // Generate version for tool set based on children - const toolSetVersion = generateToolSetVersion(children); + const toolSetVersion = generateToolSetVersion(children) ?? ''; tools.push({ ...rootMod, diff --git a/modules/tool/build/build-json.ts b/modules/tool/build/build-json.ts index f7c726e1..0f3ba288 100644 --- a/modules/tool/build/build-json.ts +++ b/modules/tool/build/build-json.ts @@ -59,7 +59,7 @@ const LoadToolsDev = async (filename: string): Promise => { } // Generate version for tool set based on children - const toolSetVersion = generateToolSetVersion(children); + const toolSetVersion = generateToolSetVersion(children) ?? ''; tools.push({ ...rootMod, diff --git a/sdk/package.json b/sdk/package.json index 077988fe..bd9d4158 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@fastgpt-sdk/plugin", - "version": "0.2.15", + "version": "0.2.16", "description": "fastgpt-plugin sdk", "main": "dist/client.js", "types": "dist/client.d.ts", From dc1e6a69562a61cff98b017be8735a9318ad65d4 Mon Sep 17 00:00:00 2001 From: FinleyGe Date: Wed, 19 Nov 2025 16:15:30 +0800 Subject: [PATCH 4/4] fix: version compute logic --- modules/tool/parseMod.ts | 4 ++-- modules/tool/utils/tool.ts | 16 ++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/modules/tool/parseMod.ts b/modules/tool/parseMod.ts index 98c15bbd..d622c0bd 100644 --- a/modules/tool/parseMod.ts +++ b/modules/tool/parseMod.ts @@ -30,7 +30,7 @@ export const parseMod = async ({ const childIcon = child.icon || rootMod.icon || getIconPath(`${childToolId}/logo`); // Generate version for child tool - const childVersion = child.version ?? ''; + const childVersion = generateToolVersion(child.versionList); tools.push({ ...child, toolId: childToolId, @@ -67,7 +67,7 @@ export const parseMod = async ({ icon, toolId, toolFilename: filename, - version: rootMod.version ?? '' + version: generateToolVersion(rootMod.versionList) }); } return tools; diff --git a/modules/tool/utils/tool.ts b/modules/tool/utils/tool.ts index d7ca3314..6b4c892c 100644 --- a/modules/tool/utils/tool.ts +++ b/modules/tool/utils/tool.ts @@ -47,14 +47,7 @@ export const exportToolSet = ({ config }: { config: ToolSetConfigType }) => { }; }; -/** - * Generate version hash for a single tool based on versionList - * @param versionList - Array of version objects with value field - * @returns First 8 characters of SHA256 hash of concatenated version values - */ -export function generateToolVersion( - versionList: Array<{ value: string; description?: string; inputs: any[]; outputs: any[] }> -): string { +export function generateToolVersion(versionList: Array<{ value: string }>): string { const versionString = versionList.map((v) => v.value).join(''); return createHash('sha256').update(versionString).digest('hex').substring(0, 8); } @@ -69,11 +62,10 @@ export function generateToolSetVersion(children: ToolType[]) { return undefined; } - const childVersions = children.map((child) => child.version || '').sort(); + const childVersions = children + .map((child) => generateToolVersion(child.versionList) || '') + .sort(); const versionString = childVersions.join(''); - if (versionString.length === 0) { - return undefined; - } return createHash('sha256').update(versionString).digest('hex').substring(0, 8); }