Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
38f6f9dd
authored
Mar 11, 2026
by
Archer
Committed by
GitHub
Mar 11, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: tool id (#6544)
* fix: tool id * fix: test * fix: ts * add test
parent
960c8898
Show whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
427 additions
and
232 deletions
+427
-232
document/content/docs/self-host/upgrading/4-14/4149.mdx
+17
-0
document/content/docs/toc.mdx
+1
-0
document/data/doc-last-modified.json
+6
-5
packages/global/common/error/code/plugin.ts
+1
-1
packages/global/core/app/tool/httpTool/utils.ts
+4
-2
packages/global/core/app/tool/mcpTool/utils.ts
+6
-7
packages/global/core/app/tool/utils.ts
+39
-18
packages/global/core/workflow/type/node.ts
+2
-3
packages/service/core/app/tool/controller.ts
+16
-87
packages/service/core/app/tool/runtime/utils.ts
+6
-1
packages/service/core/app/utils.ts
+1
-1
packages/service/core/plugin/tool/systemToolSchema.ts
+1
-0
packages/service/core/workflow/dispatch/ai/agent/sub/tool/index.ts
+3
-4
packages/service/core/workflow/dispatch/ai/agent/sub/tool/utils.ts
+7
-13
packages/service/core/workflow/dispatch/ai/agent/utils.ts
+2
-2
packages/service/core/workflow/dispatch/child/runTool.ts
+15
-5
packages/service/core/workflow/dispatch/plugin/run.ts
+51
-28
packages/service/core/workflow/dispatch/utils.ts
+8
-13
packages/service/support/permission/app/auth.ts
+2
-7
packages/web/i18n/en/common.json
+1
-1
packages/web/i18n/zh-CN/common.json
+1
-1
packages/web/i18n/zh-Hant/common.json
+1
-1
projects/app/package.json
+1
-1
projects/app/src/pages/api/core/app/mcpTools/create.ts
+1
-2
projects/app/src/pages/api/core/app/mcpTools/update.ts
+1
-2
projects/app/src/pages/api/core/app/tool/getVersionList.ts
+1
-1
test/cases/global/core/app/tool/httpTool/utils.test.ts
+7
-4
test/cases/global/core/app/tool/mcpTool/utils.test.ts
+10
-9
test/cases/global/core/app/tool/utils.test.ts
+11
-13
test/cases/service/core/workflow/dispatch/tools/runTool.test.ts
+204
-0
No files found.
document/content/docs/self-host/upgrading/4-14/4149.mdx
0 → 100644
View file @
38f6f9dd
---
title: 'V4.14.9(进行中)'
description: 'FastGPT V4.14.9 更新说明'
---
## 🚀 新增内容
## ⚙️ 优化
## 🐛 修复
1. 工作流嵌套插件时,未成功保留插件运行详情。同时整理所有 tool 类型前缀。
2. 更新 MCP toolset 后可能无法正常调用。
\ No newline at end of file
document/content/docs/toc.mdx
View file @
38f6f9dd
...
@@ -120,6 +120,7 @@ description: FastGPT 文档目录
...
@@ -120,6 +120,7 @@ description: FastGPT 文档目录
- [/docs/self-host/upgrading/4-14/4147](/docs/self-host/upgrading/4-14/4147)
- [/docs/self-host/upgrading/4-14/4147](/docs/self-host/upgrading/4-14/4147)
- [/docs/self-host/upgrading/4-14/4148](/docs/self-host/upgrading/4-14/4148)
- [/docs/self-host/upgrading/4-14/4148](/docs/self-host/upgrading/4-14/4148)
- [/docs/self-host/upgrading/4-14/41481](/docs/self-host/upgrading/4-14/41481)
- [/docs/self-host/upgrading/4-14/41481](/docs/self-host/upgrading/4-14/41481)
- [/docs/self-host/upgrading/4-14/4149](/docs/self-host/upgrading/4-14/4149)
- [/docs/self-host/upgrading/outdated/40](/docs/self-host/upgrading/outdated/40)
- [/docs/self-host/upgrading/outdated/40](/docs/self-host/upgrading/outdated/40)
- [/docs/self-host/upgrading/outdated/41](/docs/self-host/upgrading/outdated/41)
- [/docs/self-host/upgrading/outdated/41](/docs/self-host/upgrading/outdated/41)
- [/docs/self-host/upgrading/outdated/4100](/docs/self-host/upgrading/outdated/4100)
- [/docs/self-host/upgrading/outdated/4100](/docs/self-host/upgrading/outdated/4100)
...
...
document/data/doc-last-modified.json
View file @
38f6f9dd
...
@@ -95,8 +95,8 @@
...
@@ -95,8 +95,8 @@
"document/content/docs/introduction/guide/dashboard/workflow/variable_update.mdx"
:
"2025-07-23T21:35:03+08:00"
,
"document/content/docs/introduction/guide/dashboard/workflow/variable_update.mdx"
:
"2025-07-23T21:35:03+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/RAG.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/RAG.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/RAG.mdx"
:
"2025-07-23T21:35:03+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/RAG.mdx"
:
"2025-07-23T21:35:03+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/api_dataset.en.mdx"
:
"2026-0
2-26T22:14:30
+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/api_dataset.en.mdx"
:
"2026-0
3-09T17:39:53
+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/api_dataset.mdx"
:
"202
5-07-23T21:35:0
3+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/api_dataset.mdx"
:
"202
6-03-09T17:39:5
3+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/collection_tags.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/collection_tags.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/collection_tags.mdx"
:
"2025-08-02T19:38:37+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/collection_tags.mdx"
:
"2025-08-02T19:38:37+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/dataset_engine.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
"document/content/docs/introduction/guide/knowledge_base/dataset_engine.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
...
@@ -232,9 +232,10 @@
...
@@ -232,9 +232,10 @@
"document/content/docs/self-host/upgrading/4-14/4147.en.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/4-14/4147.en.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/4-14/4147.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/4-14/4147.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/4-14/4148.en.mdx"
:
"2026-03-06T19:32:23+08:00"
,
"document/content/docs/self-host/upgrading/4-14/4148.en.mdx"
:
"2026-03-06T19:32:23+08:00"
,
"document/content/docs/self-host/upgrading/4-14/4148.mdx"
:
"2026-03-09T1
2:04:22
+08:00"
,
"document/content/docs/self-host/upgrading/4-14/4148.mdx"
:
"2026-03-09T1
7:39:53
+08:00"
,
"document/content/docs/self-host/upgrading/4-14/41481.en.mdx"
:
"2026-03-09T12:02:02+08:00"
,
"document/content/docs/self-host/upgrading/4-14/41481.en.mdx"
:
"2026-03-09T12:02:02+08:00"
,
"document/content/docs/self-host/upgrading/4-14/41481.mdx"
:
"2026-03-09T14:24:27+08:00"
,
"document/content/docs/self-host/upgrading/4-14/41481.mdx"
:
"2026-03-09T17:39:53+08:00"
,
"document/content/docs/self-host/upgrading/4-14/4149.mdx"
:
"2026-03-11T22:47:07+08:00"
,
"document/content/docs/self-host/upgrading/outdated/40.en.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/outdated/40.en.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/outdated/40.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/outdated/40.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/outdated/41.en.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/outdated/41.en.mdx"
:
"2026-03-03T17:39:47+08:00"
,
...
@@ -376,7 +377,7 @@
...
@@ -376,7 +377,7 @@
"document/content/docs/self-host/upgrading/upgrade-intruction.en.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/upgrade-intruction.en.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/upgrade-intruction.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/self-host/upgrading/upgrade-intruction.mdx"
:
"2026-03-03T17:39:47+08:00"
,
"document/content/docs/toc.en.mdx"
:
"2026-03-09T12:02:02+08:00"
,
"document/content/docs/toc.en.mdx"
:
"2026-03-09T12:02:02+08:00"
,
"document/content/docs/toc.mdx"
:
"2026-03-
09T12:02:02
+08:00"
,
"document/content/docs/toc.mdx"
:
"2026-03-
11T22:47:07
+08:00"
,
"document/content/docs/use-cases/app-cases/dalle3.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
"document/content/docs/use-cases/app-cases/dalle3.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
"document/content/docs/use-cases/app-cases/dalle3.mdx"
:
"2025-07-23T21:35:03+08:00"
,
"document/content/docs/use-cases/app-cases/dalle3.mdx"
:
"2025-07-23T21:35:03+08:00"
,
"document/content/docs/use-cases/app-cases/english_essay_correction_bot.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
"document/content/docs/use-cases/app-cases/english_essay_correction_bot.en.mdx"
:
"2026-02-26T22:14:30+08:00"
,
...
...
packages/global/common/error/code/plugin.ts
View file @
38f6f9dd
...
@@ -9,7 +9,7 @@ export enum PluginErrEnum {
...
@@ -9,7 +9,7 @@ export enum PluginErrEnum {
const
errList
=
[
const
errList
=
[
{
{
statusText
:
PluginErrEnum
.
unExist
,
statusText
:
PluginErrEnum
.
unExist
,
message
:
i18nT
(
'common:
code_error.plugin_error.
not_exist'
)
message
:
i18nT
(
'common:
error.tool_
not_exist'
)
},
},
{
{
statusText
:
PluginErrEnum
.
unAuth
,
statusText
:
PluginErrEnum
.
unAuth
,
...
...
packages/global/core/app/tool/httpTool/utils.ts
View file @
38f6f9dd
...
@@ -51,12 +51,14 @@ export const getHTTPToolRuntimeNode = ({
...
@@ -51,12 +51,14 @@ export const getHTTPToolRuntimeNode = ({
tool
,
tool
,
nodeId
,
nodeId
,
avatar
=
'core/app/type/httpToolsFill'
,
avatar
=
'core/app/type/httpToolsFill'
,
toolSetId
toolSetId
,
toolsetName
}:
{
}:
{
tool
:
Omit
<
HttpToolConfigType
,
'path'
|
'method'
>
;
tool
:
Omit
<
HttpToolConfigType
,
'path'
|
'method'
>
;
nodeId
:
string
;
nodeId
:
string
;
avatar
?:
string
;
avatar
?:
string
;
toolSetId
:
string
;
toolSetId
:
string
;
toolsetName
:
string
;
}):
RuntimeNodeItemType
=>
{
}):
RuntimeNodeItemType
=>
{
return
{
return
{
nodeId
,
nodeId
,
...
@@ -81,7 +83,7 @@ export const getHTTPToolRuntimeNode = ({
...
@@ -81,7 +83,7 @@ export const getHTTPToolRuntimeNode = ({
type
:
FlowNodeOutputTypeEnum
.
static
type
:
FlowNodeOutputTypeEnum
.
static
}
}
],
],
name
:
tool
.
name
,
name
:
`
${
toolsetName
}
/
${
tool
.
name
}
`
,
version
:
''
version
:
''
};
};
};
};
...
...
packages/global/core/app/tool/mcpTool/utils.ts
View file @
38f6f9dd
...
@@ -13,15 +13,13 @@ export const getMCPToolSetRuntimeNode = ({
...
@@ -13,15 +13,13 @@ export const getMCPToolSetRuntimeNode = ({
toolList
,
toolList
,
headerSecret
,
headerSecret
,
name
,
name
,
avatar
,
avatar
toolId
}:
{
}:
{
url
:
string
;
url
:
string
;
toolList
:
McpToolConfigType
[];
toolList
:
McpToolConfigType
[];
headerSecret
?:
StoreSecretValueType
;
headerSecret
?:
StoreSecretValueType
;
name
?:
string
;
name
?:
string
;
avatar
?:
string
;
avatar
?:
string
;
toolId
:
string
;
}):
RuntimeNodeItemType
=>
{
}):
RuntimeNodeItemType
=>
{
return
{
return
{
nodeId
:
getNanoid
(
16
),
nodeId
:
getNanoid
(
16
),
...
@@ -32,8 +30,7 @@ export const getMCPToolSetRuntimeNode = ({
...
@@ -32,8 +30,7 @@ export const getMCPToolSetRuntimeNode = ({
mcpToolSet
:
{
mcpToolSet
:
{
toolList
,
toolList
,
headerSecret
,
headerSecret
,
url
,
url
toolId
}
}
},
},
inputs
:
[],
inputs
:
[],
...
@@ -47,12 +44,14 @@ export const getMCPToolRuntimeNode = ({
...
@@ -47,12 +44,14 @@ export const getMCPToolRuntimeNode = ({
tool
,
tool
,
avatar
=
'core/app/type/mcpToolsFill'
,
avatar
=
'core/app/type/mcpToolsFill'
,
nodeId
,
nodeId
,
toolsetName
,
toolSetId
toolSetId
}:
{
}:
{
nodeId
:
string
;
nodeId
:
string
;
tool
:
McpToolConfigType
;
tool
:
McpToolConfigType
;
avatar
?:
string
;
toolSetId
:
string
;
toolSetId
:
string
;
toolsetName
:
string
;
avatar
?:
string
;
}):
RuntimeNodeItemType
=>
{
}):
RuntimeNodeItemType
=>
{
return
{
return
{
nodeId
,
nodeId
,
...
@@ -76,7 +75,7 @@ export const getMCPToolRuntimeNode = ({
...
@@ -76,7 +75,7 @@ export const getMCPToolRuntimeNode = ({
type
:
FlowNodeOutputTypeEnum
.
static
type
:
FlowNodeOutputTypeEnum
.
static
}
}
],
],
name
:
tool
.
name
,
name
:
`
${
toolsetName
}
/
${
tool
.
name
}
`
,
version
:
''
version
:
''
};
};
};
};
...
...
packages/global/core/app/tool/utils.ts
View file @
38f6f9dd
...
@@ -2,60 +2,81 @@ import { AppToolSourceEnum } from '../tool/constants';
...
@@ -2,60 +2,81 @@ import { AppToolSourceEnum } from '../tool/constants';
/**
/**
Tool id rule:
Tool id rule:
- personal: ObjectId
- personal: ObjectId
(旧版), personal-objectId(新版)
- commercial: commercial-ObjectId
- commercial: commercial-ObjectId
- systemtool: systemTool-id
- systemtool: systemTool-id
- mcp tool: mcp-parentId/toolName
- mcp toolset: appId
- mcp tool pluginId: mcp-appId/toolname
- http toolset: appId
- http tool pluginId: http-appId/toolname
(deprecated) community: community-id
(deprecated) community: community-id
*/
*/
export
function
splitCombineToolId
(
id
:
string
)
{
export
function
splitCombineToolId
(
id
:
string
):
{
source
:
AppToolSourceEnum
;
pluginId
:
string
;
authAppId
?:
string
;
}
{
const
splitRes
=
id
.
split
(
'-'
);
const
splitRes
=
id
.
split
(
'-'
);
if
(
splitRes
.
length
===
1
)
{
if
(
splitRes
.
length
===
1
)
{
// app id
// app id
return
{
return
{
source
:
AppToolSourceEnum
.
personal
,
source
:
AppToolSourceEnum
.
personal
,
pluginId
:
id
pluginId
:
id
,
authAppId
:
id
};
};
}
}
const
[
source
,
...
rest
]
=
id
.
split
(
'-'
)
as
[
AppToolSourceEnum
,
string
|
undefined
];
const
[
source
,
...
rest
]
=
id
.
split
(
'-'
)
as
[
AppToolSourceEnum
,
string
|
undefined
];
const
plugin
Id
=
rest
.
join
(
'-'
);
const
tool
Id
=
rest
.
join
(
'-'
);
if
(
!
source
||
!
pluginId
)
throw
new
Error
(
'plugin
Id not found'
);
if
(
!
source
||
!
toolId
)
throw
new
Error
(
'tool
Id not found'
);
// 兼容4.10.0 之前的插件
// 兼容4.10.0 之前的插件
if
(
source
===
'community'
||
id
===
'commercial-dalle3'
)
{
if
(
source
===
'community'
||
id
===
'commercial-dalle3'
)
{
return
{
return
{
source
:
AppToolSourceEnum
.
systemTool
,
source
:
AppToolSourceEnum
.
systemTool
,
pluginId
:
`
${
AppToolSourceEnum
.
systemTool
}
-
${
pluginId
}
`
pluginId
:
toolId
};
}
if
(
source
===
AppToolSourceEnum
.
systemTool
)
{
return
{
source
:
AppToolSourceEnum
.
systemTool
,
pluginId
:
toolId
};
}
if
(
source
===
AppToolSourceEnum
.
commercial
)
{
return
{
source
:
AppToolSourceEnum
.
commercial
,
pluginId
:
toolId
};
};
}
}
// mcp-appId, mcp-appId/toolname
// mcp-appId, mcp-appId/toolname
if
(
source
===
'mcp'
)
{
if
(
source
===
AppToolSourceEnum
.
mcp
)
{
const
[
parentId
,
toolName
]
=
plugin
Id
.
split
(
'/'
);
const
[
parentId
,
toolName
]
=
tool
Id
.
split
(
'/'
);
return
{
return
{
source
:
AppToolSourceEnum
.
mcp
,
source
:
AppToolSourceEnum
.
mcp
,
pluginId
,
pluginId
:
toolId
,
authAppId
:
parentId
authAppId
:
parentId
};
};
}
}
if
(
source
===
'http'
)
{
if
(
source
===
AppToolSourceEnum
.
http
)
{
const
[
parentId
,
toolName
]
=
plugin
Id
.
split
(
'/'
);
const
[
parentId
,
toolName
]
=
tool
Id
.
split
(
'/'
);
return
{
return
{
source
:
AppToolSourceEnum
.
http
,
source
:
AppToolSourceEnum
.
http
,
pluginId
,
pluginId
:
toolId
,
parentId
authAppId
:
parentId
};
};
}
}
if
(
source
===
'personal'
)
{
if
(
source
===
AppToolSourceEnum
.
personal
)
{
return
{
return
{
source
:
AppToolSourceEnum
.
personal
,
source
:
AppToolSourceEnum
.
personal
,
pluginId
,
pluginId
:
toolId
,
parentId
:
plugin
Id
authAppId
:
tool
Id
};
};
}
}
return
{
source
,
pluginId
:
id
}
;
throw
new
Error
(
'Invalid tool id'
)
;
}
}
export
const
getToolRawId
=
(
id
:
string
)
=>
{
export
const
getToolRawId
=
(
id
:
string
)
=>
{
...
...
packages/global/core/workflow/type/node.ts
View file @
38f6f9dd
...
@@ -12,7 +12,6 @@ import z from 'zod';
...
@@ -12,7 +12,6 @@ import z from 'zod';
export
const
NodeToolConfigTypeSchema
=
z
.
object
({
export
const
NodeToolConfigTypeSchema
=
z
.
object
({
mcpToolSet
:
z
mcpToolSet
:
z
.
object
({
.
object
({
toolId
:
z
.
string
(),
url
:
z
.
string
(),
url
:
z
.
string
(),
headerSecret
:
StoreSecretValueTypeSchema
.
optional
(),
headerSecret
:
StoreSecretValueTypeSchema
.
optional
(),
toolList
:
z
.
array
(
McpToolConfigSchema
)
toolList
:
z
.
array
(
McpToolConfigSchema
)
...
@@ -20,7 +19,7 @@ export const NodeToolConfigTypeSchema = z.object({
...
@@ -20,7 +19,7 @@ export const NodeToolConfigTypeSchema = z.object({
.
optional
(),
.
optional
(),
mcpTool
:
z
mcpTool
:
z
.
object
({
.
object
({
toolId
:
z
.
string
()
toolId
:
z
.
string
()
// mcp-appId/oolname
})
})
.
optional
(),
.
optional
(),
systemTool
:
z
systemTool
:
z
...
@@ -51,7 +50,7 @@ export const NodeToolConfigTypeSchema = z.object({
...
@@ -51,7 +50,7 @@ export const NodeToolConfigTypeSchema = z.object({
.
optional
(),
.
optional
(),
httpTool
:
z
httpTool
:
z
.
object
({
.
object
({
toolId
:
z
.
string
()
toolId
:
z
.
string
()
// http-appId/oolname
})
})
.
optional
()
.
optional
()
});
});
...
...
packages/service/core/app/tool/controller.ts
View file @
38f6f9dd
...
@@ -239,10 +239,10 @@ export const getSystemToolsWithInstalled = async ({
...
@@ -239,10 +239,10 @@ export const getSystemToolsWithInstalled = async ({
};
};
export
const
getSystemToolByIdAndVersionId
=
async
(
export
const
getSystemToolByIdAndVersionId
=
async
(
plugin
Id
:
string
,
tool
Id
:
string
,
versionId
?:
string
versionId
?:
string
):
Promise
<
ChildAppType
>
=>
{
):
Promise
<
ChildAppType
>
=>
{
const
tool
=
await
getSystemToolById
(
plugin
Id
);
const
tool
=
await
getSystemToolById
(
tool
Id
);
// App type system tool
// App type system tool
if
(
tool
.
associatedPluginId
)
{
if
(
tool
.
associatedPluginId
)
{
...
@@ -333,10 +333,6 @@ export const getSystemToolByIdAndVersionId = async (
...
@@ -333,10 +333,6 @@ export const getSystemToolByIdAndVersionId = async (
/*
/*
Format plugin to workflow preview node data
Format plugin to workflow preview node data
Persion workflow/plugin: objectId
Persion mcptoolset: objectId
Persion mcp tool: mcp-parentId/name
System tool/toolset: system-toolId
*/
*/
export
async
function
getChildAppPreviewNode
({
export
async
function
getChildAppPreviewNode
({
appId
,
appId
,
...
@@ -350,8 +346,7 @@ export async function getChildAppPreviewNode({
...
@@ -350,8 +346,7 @@ export async function getChildAppPreviewNode({
const
{
source
,
pluginId
}
=
splitCombineToolId
(
appId
);
const
{
source
,
pluginId
}
=
splitCombineToolId
(
appId
);
const
app
:
ChildAppType
=
await
(
async
()
=>
{
const
app
:
ChildAppType
=
await
(
async
()
=>
{
// 1. App
// App / Mcp toolset / Http toolset
// 2. MCP ToolSets
if
(
source
===
AppToolSourceEnum
.
personal
)
{
if
(
source
===
AppToolSourceEnum
.
personal
)
{
const
item
=
await
MongoApp
.
findById
(
pluginId
).
lean
();
const
item
=
await
MongoApp
.
findById
(
pluginId
).
lean
();
if
(
!
item
)
return
Promise
.
reject
(
PluginErrEnum
.
unExist
);
if
(
!
item
)
return
Promise
.
reject
(
PluginErrEnum
.
unExist
);
...
@@ -367,17 +362,18 @@ export async function getChildAppPreviewNode({
...
@@ -367,17 +362,18 @@ export async function getChildAppPreviewNode({
})
})
:
true
;
:
true
;
if
(
item
.
type
===
AppTypeEnum
.
mcpToolSet
)
{
// Adapt
if
(
item
.
type
===
AppTypeEnum
.
mcpToolSet
&&
!
version
.
nodes
[
0
].
toolConfig
)
{
const
children
=
await
getMCPChildren
(
item
);
const
children
=
await
getMCPChildren
(
item
);
version
.
nodes
[
0
].
toolConfig
=
{
version
.
nodes
[
0
].
toolConfig
=
{
mcpToolSet
:
{
mcpToolSet
:
{
toolId
:
pluginId
,
toolList
:
children
,
toolList
:
children
,
url
:
''
,
url
:
''
,
headerSecret
:
{}
headerSecret
:
{}
}
}
};
};
}
}
return
{
return
{
id
:
String
(
item
.
_id
),
id
:
String
(
item
.
_id
),
teamId
:
String
(
item
.
teamId
),
teamId
:
String
(
item
.
teamId
),
...
@@ -430,11 +426,12 @@ export async function getChildAppPreviewNode({
...
@@ -430,11 +426,12 @@ export async function getChildAppPreviewNode({
getMCPToolRuntimeNode
({
getMCPToolRuntimeNode
({
nodeId
:
getNanoid
(
6
),
nodeId
:
getNanoid
(
6
),
toolSetId
:
item
.
_id
,
toolSetId
:
item
.
_id
,
toolsetName
:
item
.
name
,
avatar
:
item
.
avatar
,
avatar
:
item
.
avatar
,
tool
:
{
tool
:
{
description
:
tool
.
description
,
description
:
tool
.
description
,
inputSchema
:
tool
.
inputSchema
,
inputSchema
:
tool
.
inputSchema
,
name
:
`
${
item
.
name
}
/
${
tool
.
name
}
`
name
:
tool
.
name
}
}
})
})
],
],
...
@@ -469,11 +466,12 @@ export async function getChildAppPreviewNode({
...
@@ -469,11 +466,12 @@ export async function getChildAppPreviewNode({
getHTTPToolRuntimeNode
({
getHTTPToolRuntimeNode
({
nodeId
:
getNanoid
(
6
),
nodeId
:
getNanoid
(
6
),
toolSetId
:
item
.
_id
,
toolSetId
:
item
.
_id
,
toolsetName
:
item
.
name
,
tool
:
{
tool
:
{
description
:
tool
.
description
,
description
:
tool
.
description
,
inputSchema
:
tool
.
inputSchema
,
inputSchema
:
tool
.
inputSchema
,
outputSchema
:
tool
.
outputSchema
,
outputSchema
:
tool
.
outputSchema
,
name
:
`
${
item
.
name
}
/
${
tool
.
name
}
`
name
:
tool
.
name
},
},
avatar
:
item
.
avatar
avatar
:
item
.
avatar
})
})
...
@@ -484,10 +482,9 @@ export async function getChildAppPreviewNode({
...
@@ -484,10 +482,9 @@ export async function getChildAppPreviewNode({
isLatestVersion
:
true
isLatestVersion
:
true
};
};
}
}
// 1. System Tools
// System Tools/ Commercial system tools
// 2. System Plugins configured in Pro (has associatedPluginId)
else
{
else
{
return
getSystemToolByIdAndVersionId
(
plugin
Id
,
versionId
);
return
getSystemToolByIdAndVersionId
(
app
Id
,
versionId
);
}
}
})();
})();
...
@@ -504,7 +501,7 @@ export async function getChildAppPreviewNode({
...
@@ -504,7 +501,7 @@ export async function getChildAppPreviewNode({
if
(
source
===
AppToolSourceEnum
.
systemTool
)
{
if
(
source
===
AppToolSourceEnum
.
systemTool
)
{
// system Tool or Toolsets
// system Tool or Toolsets
const
children
=
app
.
isFolder
const
children
=
app
.
isFolder
?
(
await
getSystemTools
()).
filter
((
item
)
=>
item
.
parentId
===
pluginI
d
)
?
(
await
getSystemTools
()).
filter
((
item
)
=>
item
.
parentId
===
app
.
i
d
)
:
[];
:
[];
return
{
return
{
...
@@ -619,74 +616,6 @@ export async function getChildAppPreviewNode({
...
@@ -619,74 +616,6 @@ export async function getChildAppPreviewNode({
};
};
}
}
/**
Get runtime plugin data
System plugin: plugin id
Personal plugin: Version id
*/
export
async
function
getChildAppRuntimeById
({
id
,
versionId
,
lang
=
'en'
}:
{
id
:
string
;
versionId
?:
string
;
lang
?:
localeType
;
}):
Promise
<
AppToolRuntimeType
>
{
const
app
=
await
(
async
()
=>
{
const
{
source
,
pluginId
}
=
splitCombineToolId
(
id
);
if
(
source
===
AppToolSourceEnum
.
personal
)
{
const
item
=
await
MongoApp
.
findById
(
pluginId
).
lean
();
if
(
!
item
)
return
Promise
.
reject
(
PluginErrEnum
.
unExist
);
const
version
=
await
getAppVersionById
({
appId
:
pluginId
,
versionId
,
app
:
item
});
return
{
id
:
String
(
item
.
_id
),
teamId
:
String
(
item
.
teamId
),
tmbId
:
String
(
item
.
tmbId
),
name
:
item
.
name
,
avatar
:
item
.
avatar
,
intro
:
item
.
intro
,
showStatus
:
true
,
workflow
:
{
nodes
:
version
.
nodes
,
edges
:
version
.
edges
,
chatConfig
:
version
.
chatConfig
},
templateType
:
FlowNodeTemplateTypeEnum
.
teamApp
,
originCost
:
0
,
currentCost
:
0
,
systemKeyCost
:
0
,
hasTokenFee
:
false
,
pluginOrder
:
0
};
}
else
{
return
getSystemToolByIdAndVersionId
(
pluginId
,
versionId
);
}
})();
return
{
id
:
app
.
id
,
teamId
:
app
.
teamId
,
tmbId
:
app
.
tmbId
,
name
:
parseI18nString
(
app
.
name
,
lang
),
avatar
:
app
.
avatar
||
''
,
showStatus
:
true
,
currentCost
:
app
.
currentCost
,
systemKeyCost
:
app
.
systemKeyCost
,
nodes
:
app
.
workflow
.
nodes
,
edges
:
app
.
workflow
.
edges
,
hasTokenFee
:
app
.
hasTokenFee
};
}
/* FastsGPT-tool api: */
/* FastsGPT-tool api: */
export
const
refreshSystemTools
=
async
():
Promise
<
AppToolTemplateItemType
[]
>
=>
{
export
const
refreshSystemTools
=
async
():
Promise
<
AppToolTemplateItemType
[]
>
=>
{
const
workflowToolFormat
=
(
item
:
SystemPluginToolCollectionType
):
AppToolTemplateItemType
=>
{
const
workflowToolFormat
=
(
item
:
SystemPluginToolCollectionType
):
AppToolTemplateItemType
=>
{
...
@@ -784,10 +713,10 @@ export const refreshSystemTools = async (): Promise<AppToolTemplateItemType[]> =
...
@@ -784,10 +713,10 @@ export const refreshSystemTools = async (): Promise<AppToolTemplateItemType[]> =
return
concatTools
;
return
concatTools
;
};
};
export
const
getSystemToolById
=
async
(
id
:
string
):
Promise
<
AppToolTemplateItemType
>
=>
{
// toolId: systemTool-id, commercial-id
const
{
pluginId
}
=
splitCombineToolId
(
id
);
export
const
getSystemToolById
=
async
(
toolId
:
string
):
Promise
<
AppToolTemplateItemType
>
=>
{
const
tools
=
await
getSystemTools
();
const
tools
=
await
getSystemTools
();
const
tool
=
tools
.
find
((
item
)
=>
item
.
id
===
plugin
Id
);
const
tool
=
tools
.
find
((
item
)
=>
item
.
id
===
tool
Id
);
if
(
tool
)
{
if
(
tool
)
{
return
cloneDeep
(
tool
);
return
cloneDeep
(
tool
);
}
}
...
...
packages/service/core/app/tool/runtime/utils.ts
View file @
38f6f9dd
...
@@ -23,7 +23,12 @@ export const computedAppToolUsage = async ({
...
@@ -23,7 +23,12 @@ export const computedAppToolUsage = async ({
const
{
source
}
=
splitCombineToolId
(
plugin
.
id
);
const
{
source
}
=
splitCombineToolId
(
plugin
.
id
);
const
childrenUsages
=
childrenUsage
.
reduce
((
sum
,
item
)
=>
sum
+
(
item
.
totalPoints
||
0
),
0
);
const
childrenUsages
=
childrenUsage
.
reduce
((
sum
,
item
)
=>
sum
+
(
item
.
totalPoints
||
0
),
0
);
if
(
source
!==
AppToolSourceEnum
.
personal
)
{
const
set
=
new
Set
([
AppToolSourceEnum
.
commercial
,
AppToolSourceEnum
.
community
,
AppToolSourceEnum
.
systemTool
]);
if
(
set
.
has
(
source
))
{
if
(
error
)
return
0
;
if
(
error
)
return
0
;
const
pluginCurrentCost
=
plugin
.
currentCost
??
0
;
const
pluginCurrentCost
=
plugin
.
currentCost
??
0
;
...
...
packages/service/core/app/utils.ts
View file @
38f6f9dd
...
@@ -82,7 +82,7 @@ export async function rewriteAppWorkflowToDetail({
...
@@ -82,7 +82,7 @@ export async function rewriteAppWorkflowToDetail({
/* Add node(App Type) versionlabel and latest sign ==== */
/* Add node(App Type) versionlabel and latest sign ==== */
await
Promise
.
all
(
await
Promise
.
all
(
nodes
.
map
(
async
(
node
)
=>
{
nodes
.
map
(
async
(
node
)
=>
{
// Tool node
(简易模式/工作流)
// Tool node
if
(
node
.
pluginId
)
{
if
(
node
.
pluginId
)
{
const
result
=
await
loadToolNode
({
id
:
node
.
pluginId
,
versionId
:
node
.
version
});
const
result
=
await
loadToolNode
({
id
:
node
.
pluginId
,
versionId
:
node
.
version
});
if
(
result
.
success
)
{
if
(
result
.
success
)
{
...
...
packages/service/core/plugin/tool/systemToolSchema.ts
View file @
38f6f9dd
...
@@ -7,6 +7,7 @@ export const collectionName = 'system_plugin_tools';
...
@@ -7,6 +7,7 @@ export const collectionName = 'system_plugin_tools';
const
SystemToolSchema
=
new
Schema
({
const
SystemToolSchema
=
new
Schema
({
pluginId
:
{
pluginId
:
{
// commercial-id
type
:
String
,
type
:
String
,
required
:
true
required
:
true
},
},
...
...
packages/service/core/workflow/dispatch/ai/agent/sub/tool/index.ts
View file @
38f6f9dd
...
@@ -20,6 +20,7 @@ import { getAppVersionById } from '../../../../../../app/version/controller';
...
@@ -20,6 +20,7 @@ import { getAppVersionById } from '../../../../../../app/version/controller';
import
{
MCPClient
}
from
'../../../../../../app/mcp'
;
import
{
MCPClient
}
from
'../../../../../../app/mcp'
;
import
{
runHTTPTool
}
from
'../../../../../../app/http'
;
import
{
runHTTPTool
}
from
'../../../../../../app/http'
;
import
{
getS3ChatSource
}
from
'../../../../../../../common/s3/sources/chat'
;
import
{
getS3ChatSource
}
from
'../../../../../../../common/s3/sources/chat'
;
import
{
parseToolId
}
from
'../../../../child/runTool'
;
type
SystemInputConfigType
=
{
type
SystemInputConfigType
=
{
type
:
SystemToolSecretInputTypeEnum
;
type
:
SystemToolSecretInputTypeEnum
;
...
@@ -175,8 +176,7 @@ export const dispatchTool = async ({
...
@@ -175,8 +176,7 @@ export const dispatchTool = async ({
]
]
};
};
}
else
if
(
toolConfig
?.
mcpTool
?.
toolId
)
{
}
else
if
(
toolConfig
?.
mcpTool
?.
toolId
)
{
const
{
pluginId
}
=
splitCombineToolId
(
toolConfig
.
mcpTool
.
toolId
);
const
{
parentId
,
toolName
}
=
parseToolId
(
toolConfig
.
mcpTool
.
toolId
);
const
[
parentId
,
toolSetName
,
toolName
]
=
pluginId
.
split
(
'/'
);
const
tool
=
await
getAppVersionById
({
const
tool
=
await
getAppVersionById
({
appId
:
parentId
,
appId
:
parentId
,
versionId
:
version
versionId
:
version
...
@@ -203,8 +203,7 @@ export const dispatchTool = async ({
...
@@ -203,8 +203,7 @@ export const dispatchTool = async ({
usages
:
[]
usages
:
[]
};
};
}
else
if
(
toolConfig
?.
httpTool
?.
toolId
)
{
}
else
if
(
toolConfig
?.
httpTool
?.
toolId
)
{
const
{
pluginId
}
=
splitCombineToolId
(
toolConfig
.
httpTool
.
toolId
);
const
{
parentId
,
toolName
}
=
parseToolId
(
toolConfig
.
httpTool
.
toolId
);
const
[
parentId
,
toolSetName
,
toolName
]
=
pluginId
.
split
(
'/'
);
if
(
!
parentId
||
!
toolName
)
{
if
(
!
parentId
||
!
toolName
)
{
return
Promise
.
reject
(
`Invalid HTTP tool id:
${
toolConfig
.
httpTool
.
toolId
}
`
);
return
Promise
.
reject
(
`Invalid HTTP tool id:
${
toolConfig
.
httpTool
.
toolId
}
`
);
}
}
...
...
packages/service/core/workflow/dispatch/ai/agent/sub/tool/utils.ts
View file @
38f6f9dd
...
@@ -25,7 +25,7 @@ import type { SubAppInitType } from '../type';
...
@@ -25,7 +25,7 @@ import type { SubAppInitType } from '../type';
import
{
getToolConfigStatus
}
from
'@fastgpt/global/core/app/formEdit/utils'
;
import
{
getToolConfigStatus
}
from
'@fastgpt/global/core/app/formEdit/utils'
;
import
{
getLogger
,
LogCategories
}
from
'../../../../../../../common/logger'
;
import
{
getLogger
,
LogCategories
}
from
'../../../../../../../common/logger'
;
export
const
agentSkillToToolRuntime
=
async
({
export
const
getAgentRuntimeTools
=
async
({
tools
,
tools
,
tmbId
,
tmbId
,
lang
lang
...
@@ -195,18 +195,15 @@ export const agentSkillToToolRuntime = async ({
...
@@ -195,18 +195,15 @@ export const agentSkillToToolRuntime = async ({
if
(
!
app
)
return
[];
if
(
!
app
)
return
[];
const
toolList
=
await
getMCPChildren
(
app
);
const
toolList
=
await
getMCPChildren
(
app
);
const
toolSetId
=
mcpToolsetVal
.
toolId
??
toolNode
.
pluginId
;
const
toolSetId
=
mcpToolsetVal
.
toolId
||
toolNode
.
pluginId
;
const
children
=
toolList
.
map
((
tool
,
index
)
=>
{
const
children
=
toolList
.
map
((
tool
,
index
)
=>
{
const
newToolNode
=
getMCPToolRuntimeNode
({
const
newToolNode
=
getMCPToolRuntimeNode
({
toolSetId
,
toolSetId
,
toolsetName
:
toolNode
.
name
,
nodeId
:
`
${
toolSetId
}${
index
}
`
,
nodeId
:
`
${
toolSetId
}${
index
}
`
,
avatar
:
toolNode
.
avatar
,
avatar
:
toolNode
.
avatar
,
tool
:
{
tool
...
tool
,
name
:
`
${
toolNode
.
name
}
/
${
tool
.
name
}
`
}
});
});
return
newToolNode
;
return
newToolNode
;
});
});
...
@@ -232,15 +229,12 @@ export const agentSkillToToolRuntime = async ({
...
@@ -232,15 +229,12 @@ export const agentSkillToToolRuntime = async ({
}
else
if
(
httpToolsetVal
)
{
}
else
if
(
httpToolsetVal
)
{
const
children
=
httpToolsetVal
.
toolList
.
map
((
tool
:
HttpToolConfigType
,
index
)
=>
{
const
children
=
httpToolsetVal
.
toolList
.
map
((
tool
:
HttpToolConfigType
,
index
)
=>
{
const
newToolNode
=
getHTTPToolRuntimeNode
({
const
newToolNode
=
getHTTPToolRuntimeNode
({
tool
:
{
tool
,
...
tool
,
name
:
`
${
toolNode
.
name
}
/
${
tool
.
name
}
`
},
nodeId
:
`
${
pluginId
}${
index
}
`
,
nodeId
:
`
${
pluginId
}${
index
}
`
,
avatar
:
toolNode
.
avatar
,
avatar
:
toolNode
.
avatar
,
toolSetId
:
pluginId
toolSetId
:
pluginId
,
toolsetName
:
toolNode
.
name
});
});
return
newToolNode
;
return
newToolNode
;
});
});
...
...
packages/service/core/workflow/dispatch/ai/agent/utils.ts
View file @
38f6f9dd
...
@@ -2,7 +2,7 @@ import type { localeType } from '@fastgpt/global/common/i18n/type';
...
@@ -2,7 +2,7 @@ import type { localeType } from '@fastgpt/global/common/i18n/type';
import
type
{
SkillToolType
}
from
'@fastgpt/global/core/ai/skill/type'
;
import
type
{
SkillToolType
}
from
'@fastgpt/global/core/ai/skill/type'
;
import
type
{
ChatCompletionTool
}
from
'@fastgpt/global/core/ai/type'
;
import
type
{
ChatCompletionTool
}
from
'@fastgpt/global/core/ai/type'
;
import
type
{
SubAppRuntimeType
}
from
'./type'
;
import
type
{
SubAppRuntimeType
}
from
'./type'
;
import
{
agentSkillToToolRuntime
}
from
'./sub/tool/utils'
;
import
{
getAgentRuntimeTools
}
from
'./sub/tool/utils'
;
import
{
readFileTool
}
from
'./sub/file/utils'
;
import
{
readFileTool
}
from
'./sub/file/utils'
;
import
{
PlanAgentTool
}
from
'./sub/plan/constants'
;
import
{
PlanAgentTool
}
from
'./sub/plan/constants'
;
import
{
datasetSearchTool
}
from
'./sub/dataset/utils'
;
import
{
datasetSearchTool
}
from
'./sub/dataset/utils'
;
...
@@ -43,7 +43,7 @@ export const getSubapps = async ({
...
@@ -43,7 +43,7 @@ export const getSubapps = async ({
}
}
/* System tool */
/* System tool */
const
formatTools
=
await
agentSkillToToolRuntime
({
const
formatTools
=
await
getAgentRuntimeTools
({
tools
,
tools
,
tmbId
,
tmbId
,
lang
lang
...
...
packages/service/core/workflow/dispatch/child/runTool.ts
View file @
38f6f9dd
...
@@ -19,7 +19,6 @@ import { getSystemToolById } from '../../../app/tool/controller';
...
@@ -19,7 +19,6 @@ import { getSystemToolById } from '../../../app/tool/controller';
import
{
textAdaptGptResponse
}
from
'@fastgpt/global/core/workflow/runtime/utils'
;
import
{
textAdaptGptResponse
}
from
'@fastgpt/global/core/workflow/runtime/utils'
;
import
{
pushTrack
}
from
'../../../../common/middle/tracks/utils'
;
import
{
pushTrack
}
from
'../../../../common/middle/tracks/utils'
;
import
{
getNodeErrResponse
}
from
'../utils'
;
import
{
getNodeErrResponse
}
from
'../utils'
;
import
{
splitCombineToolId
}
from
'@fastgpt/global/core/app/tool/utils'
;
import
{
getAppVersionById
}
from
'../../../../core/app/version/controller'
;
import
{
getAppVersionById
}
from
'../../../../core/app/version/controller'
;
import
{
runHTTPTool
}
from
'../../../app/http'
;
import
{
runHTTPTool
}
from
'../../../app/http'
;
import
{
getS3ChatSource
}
from
'../../../../common/s3/sources/chat'
;
import
{
getS3ChatSource
}
from
'../../../../common/s3/sources/chat'
;
...
@@ -207,8 +206,7 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
...
@@ -207,8 +206,7 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
};
};
}
else
if
(
toolConfig
?.
mcpTool
?.
toolId
)
{
}
else
if
(
toolConfig
?.
mcpTool
?.
toolId
)
{
// pluginId: toolSetAppId/toolsetName/toolName
// pluginId: toolSetAppId/toolsetName/toolName
const
{
pluginId
}
=
splitCombineToolId
(
toolConfig
.
mcpTool
.
toolId
);
const
{
parentId
,
toolName
}
=
parseToolId
(
toolConfig
.
mcpTool
.
toolId
);
const
[
parentId
,
toolSetName
,
toolName
]
=
pluginId
.
split
(
'/'
);
const
tool
=
await
getAppVersionById
({
const
tool
=
await
getAppVersionById
({
appId
:
parentId
,
appId
:
parentId
,
versionId
:
version
versionId
:
version
...
@@ -241,8 +239,7 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
...
@@ -241,8 +239,7 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
[
DispatchNodeResponseKeyEnum
.
toolResponses
]:
result
[
DispatchNodeResponseKeyEnum
.
toolResponses
]:
result
};
};
}
else
if
(
toolConfig
?.
httpTool
?.
toolId
)
{
}
else
if
(
toolConfig
?.
httpTool
?.
toolId
)
{
const
{
pluginId
}
=
splitCombineToolId
(
toolConfig
.
httpTool
.
toolId
);
const
{
parentId
,
toolName
}
=
parseToolId
(
toolConfig
.
httpTool
.
toolId
);
const
[
parentId
,
toolSetName
,
toolName
]
=
pluginId
.
split
(
'/'
);
const
toolset
=
await
getAppVersionById
({
const
toolset
=
await
getAppVersionById
({
appId
:
parentId
,
appId
:
parentId
,
versionId
:
version
versionId
:
version
...
@@ -347,3 +344,16 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
...
@@ -347,3 +344,16 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
});
});
}
}
};
};
export
const
parseToolId
=
(
id
:
string
)
=>
{
const
formatId
=
id
.
split
(
'-'
).
slice
(
1
).
join
(
'-'
);
const
[
parentId
,
toolsetNameOrToolName
,
legacyToolName
]
=
formatId
.
split
(
'/'
);
if
(
legacyToolName
)
{
// 旧版格式: source-appId/toolsetName/toolName
return
{
parentId
,
toolName
:
legacyToolName
};
}
// 新版格式: source-appId/toolName
return
{
parentId
,
toolName
:
toolsetNameOrToolName
};
};
packages/service/core/workflow/dispatch/plugin/run.ts
View file @
38f6f9dd
...
@@ -14,18 +14,22 @@ import {
...
@@ -14,18 +14,22 @@ import {
storeNodes2RuntimeNodes
storeNodes2RuntimeNodes
}
from
'@fastgpt/global/core/workflow/runtime/utils'
;
}
from
'@fastgpt/global/core/workflow/runtime/utils'
;
import
{
type
DispatchNodeResultType
}
from
'@fastgpt/global/core/workflow/runtime/type'
;
import
{
type
DispatchNodeResultType
}
from
'@fastgpt/global/core/workflow/runtime/type'
;
import
{
auth
Plugin
ByTmbId
}
from
'../../../../support/permission/app/auth'
;
import
{
auth
WorkflowTool
ByTmbId
}
from
'../../../../support/permission/app/auth'
;
import
{
ReadPermissionVal
}
from
'@fastgpt/global/support/permission/constant'
;
import
{
ReadPermissionVal
}
from
'@fastgpt/global/support/permission/constant'
;
import
{
computedAppToolUsage
}
from
'../../../app/tool/runtime/utils'
;
import
{
computedAppToolUsage
}
from
'../../../app/tool/runtime/utils'
;
import
{
filterSystemVariables
,
getNodeErrResponse
}
from
'../utils'
;
import
{
filterSystemVariables
,
getNodeErrResponse
}
from
'../utils'
;
import
{
serverGetWorkflowToolRunUserQuery
}
from
'../../../app/tool/workflowTool/utils'
;
import
{
serverGetWorkflowToolRunUserQuery
}
from
'../../../app/tool/workflowTool/utils'
;
import
type
{
NodeInputKeyEnum
,
NodeOutputKeyEnum
}
from
'@fastgpt/global/core/workflow/constants'
;
import
{
import
{
getChildAppRuntimeById
}
from
'../../../app/tool/controller'
;
type
NodeInputKeyEnum
,
type
NodeOutputKeyEnum
}
from
'@fastgpt/global/core/workflow/constants'
;
import
{
runWorkflow
}
from
'../index'
;
import
{
runWorkflow
}
from
'../index'
;
import
{
getUserChatInfo
}
from
'../../../../support/user/team/utils'
;
import
{
getUserChatInfo
}
from
'../../../../support/user/team/utils'
;
import
{
dispatchRunTool
}
from
'../child/runTool'
;
import
{
dispatchRunTool
}
from
'../child/runTool'
;
import
type
{
AppToolRuntimeType
}
from
'@fastgpt/global/core/app/tool/type'
;
import
type
{
AppToolRuntimeType
}
from
'@fastgpt/global/core/app/tool/type'
;
import
{
anyValueDecrypt
}
from
'../../../../common/secret/utils'
;
import
{
anyValueDecrypt
}
from
'../../../../common/secret/utils'
;
import
{
getAppVersionById
}
from
'../../../app/version/controller'
;
import
{
parseI18nString
}
from
'@fastgpt/global/common/i18n/utils'
;
type
RunPluginProps
=
ModuleDispatchProps
<
{
type
RunPluginProps
=
ModuleDispatchProps
<
{
[
NodeInputKeyEnum
.
forbidStream
]?:
boolean
;
[
NodeInputKeyEnum
.
forbidStream
]?:
boolean
;
...
@@ -51,7 +55,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
...
@@ -51,7 +55,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
return
getNodeErrResponse
({
error
:
'pluginId can not find'
});
return
getNodeErrResponse
({
error
:
'pluginId can not find'
});
}
}
let
plugin
:
AppToolRuntimeType
|
undefined
;
let
workflowTool
:
AppToolRuntimeType
|
undefined
;
try
{
try
{
// Adapt <= 4.10 system tool
// Adapt <= 4.10 system tool
...
@@ -70,33 +74,55 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
...
@@ -70,33 +74,55 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
});
});
}
}
if
(
source
!==
AppToolSourceEnum
.
commercial
&&
source
!==
AppToolSourceEnum
.
personal
)
{
return
getNodeErrResponse
({
error
:
'pluginId can not find'
});
}
/*
/*
1. Team app
1. Team app
2. Admin selected system tool
2. Admin selected system tool
*/
*/
const
{
files
}
=
chatValue2RuntimePrompt
(
query
);
const
{
files
}
=
chatValue2RuntimePrompt
(
query
);
// auth
plugin
// auth
workflowTool
const
pluginData
=
await
authPlugin
ByTmbId
({
const
toolData
=
await
authWorkflowTool
ByTmbId
({
appId
:
p
luginId
,
appId
:
formatP
luginId
,
tmbId
:
runningAppInfo
.
tmbId
,
tmbId
:
runningAppInfo
.
tmbId
,
per
:
ReadPermissionVal
per
:
ReadPermissionVal
});
});
plugin
=
await
getChildAppRuntimeById
({
id
:
pluginId
,
versionId
:
version
});
const
toolVersion
=
await
getAppVersionById
({
appId
:
toolData
.
_id
,
versionId
:
version
,
app
:
toolData
});
workflowTool
=
{
id
:
String
(
toolData
.
_id
),
teamId
:
toolData
.
teamId
,
tmbId
:
toolData
.
tmbId
,
name
:
parseI18nString
(
toolData
.
name
,
props
.
lang
),
avatar
:
toolData
.
avatar
||
''
,
showStatus
:
true
,
currentCost
:
0
,
systemKeyCost
:
0
,
nodes
:
toolVersion
.
nodes
,
edges
:
toolVersion
.
edges
,
hasTokenFee
:
false
};
const
outputFilterMap
=
const
outputFilterMap
=
plugin
.
nodes
workflowTool
.
nodes
.
find
((
node
)
=>
node
.
flowNodeType
===
FlowNodeTypeEnum
.
pluginOutput
)
.
find
((
node
)
=>
node
.
flowNodeType
===
FlowNodeTypeEnum
.
pluginOutput
)
?.
inputs
.
reduce
<
Record
<
string
,
boolean
>>
((
acc
,
cur
)
=>
{
?.
inputs
.
reduce
<
Record
<
string
,
boolean
>>
((
acc
,
cur
)
=>
{
acc
[
cur
.
key
]
=
cur
.
isToolOutput
===
false
?
false
:
true
;
acc
[
cur
.
key
]
=
cur
.
isToolOutput
===
false
?
false
:
true
;
return
acc
;
return
acc
;
},
{})
??
{};
},
{})
??
{};
const
runtimeNodes
=
storeNodes2RuntimeNodes
(
const
runtimeNodes
=
storeNodes2RuntimeNodes
(
plugin
.
nodes
,
workflowTool
.
nodes
,
getWorkflowEntryNodeIds
(
plugin
.
nodes
)
getWorkflowEntryNodeIds
(
workflowTool
.
nodes
)
).
map
((
node
)
=>
{
).
map
((
node
)
=>
{
// Update
plugin
input value
// Update
workflowTool
input value
if
(
node
.
flowNodeType
===
FlowNodeTypeEnum
.
pluginInput
)
{
if
(
node
.
flowNodeType
===
FlowNodeTypeEnum
.
pluginInput
)
{
return
{
return
{
...
node
,
...
node
,
...
@@ -129,7 +155,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
...
@@ -129,7 +155,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
const
{
externalProvider
}
=
await
getUserChatInfo
(
runningAppInfo
.
tmbId
);
const
{
externalProvider
}
=
await
getUserChatInfo
(
runningAppInfo
.
tmbId
);
const
runtimeVariables
=
{
const
runtimeVariables
=
{
...
filterSystemVariables
(
props
.
variables
),
...
filterSystemVariables
(
props
.
variables
),
appId
:
String
(
plugin
.
id
),
appId
:
String
(
workflowTool
.
id
),
...(
externalProvider
?
externalProvider
.
externalWorkflowVariables
:
{})
...(
externalProvider
?
externalProvider
.
externalWorkflowVariables
:
{})
};
};
const
{
const
{
...
@@ -150,27 +176,27 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
...
@@ -150,27 +176,27 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
}
}
:
{}),
:
{}),
runningAppInfo
:
{
runningAppInfo
:
{
id
:
String
(
plugin
.
id
),
id
:
String
(
workflowTool
.
id
),
name
:
plugin
.
name
,
name
:
workflowTool
.
name
,
// 如果系统插件有 teamId 和 tmbId,则使用系统插件的 teamId 和 tmbId(管理员指定了插件作为系统插件)
// 如果系统插件有 teamId 和 tmbId,则使用系统插件的 teamId 和 tmbId(管理员指定了插件作为系统插件)
teamId
:
plugin
.
teamId
||
runningAppInfo
.
teamId
,
teamId
:
workflowTool
.
teamId
||
runningAppInfo
.
teamId
,
tmbId
:
plugin
.
tmbId
||
runningAppInfo
.
tmbId
,
tmbId
:
workflowTool
.
tmbId
||
runningAppInfo
.
tmbId
,
isChildApp
:
true
isChildApp
:
true
},
},
variables
:
runtimeVariables
,
variables
:
runtimeVariables
,
query
:
serverGetWorkflowToolRunUserQuery
({
query
:
serverGetWorkflowToolRunUserQuery
({
pluginInputs
:
getWorkflowToolInputsFromStoreNodes
(
plugin
.
nodes
),
pluginInputs
:
getWorkflowToolInputsFromStoreNodes
(
workflowTool
.
nodes
),
variables
:
runtimeVariables
,
variables
:
runtimeVariables
,
files
files
}).
value
,
}).
value
,
chatConfig
:
{},
chatConfig
:
{},
runtimeNodes
,
runtimeNodes
,
runtimeEdges
:
storeEdges2RuntimeEdges
(
plugin
.
edges
)
runtimeEdges
:
storeEdges2RuntimeEdges
(
workflowTool
.
edges
)
});
});
const
output
=
flowResponses
.
find
((
item
)
=>
item
.
moduleType
===
FlowNodeTypeEnum
.
pluginOutput
);
const
output
=
flowResponses
.
find
((
item
)
=>
item
.
moduleType
===
FlowNodeTypeEnum
.
pluginOutput
);
const
usagePoints
=
await
computedAppToolUsage
({
const
usagePoints
=
await
computedAppToolUsage
({
plugin
,
plugin
:
workflowTool
,
childrenUsage
:
flowUsages
,
childrenUsage
:
flowUsages
,
error
:
!!
output
?.
pluginOutput
?.
error
error
:
!!
output
?.
pluginOutput
?.
error
});
});
...
@@ -182,20 +208,17 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
...
@@ -182,20 +208,17 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
// responseData, // debug
// responseData, // debug
[
DispatchNodeResponseKeyEnum
.
runTimes
]:
runTimes
,
[
DispatchNodeResponseKeyEnum
.
runTimes
]:
runTimes
,
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
{
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
{
moduleLogo
:
plugin
.
avatar
,
moduleLogo
:
workflowTool
.
avatar
,
totalPoints
:
usagePoints
,
totalPoints
:
usagePoints
,
toolInput
:
data
,
toolInput
:
data
,
pluginOutput
:
output
?.
pluginOutput
,
pluginOutput
:
output
?.
pluginOutput
,
pluginDetail
:
pluginData
?.
permission
?.
hasWritePer
// Not system plugin
pluginDetail
:
toolData
?.
permission
?.
hasWritePer
// Not system workflowTool
?
flowResponses
.
filter
((
item
)
=>
{
?
flowResponses
const
filterArr
=
[
FlowNodeTypeEnum
.
pluginOutput
];
return
!
filterArr
.
includes
(
item
.
moduleType
as
any
);
})
:
undefined
:
undefined
},
},
[
DispatchNodeResponseKeyEnum
.
nodeDispatchUsages
]:
[
[
DispatchNodeResponseKeyEnum
.
nodeDispatchUsages
]:
[
{
{
moduleName
:
plugin
.
name
,
moduleName
:
workflowTool
.
name
,
totalPoints
:
usagePoints
totalPoints
:
usagePoints
}
}
],
],
...
@@ -212,7 +235,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
...
@@ -212,7 +235,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
}
catch
(
error
)
{
}
catch
(
error
)
{
return
getNodeErrResponse
({
return
getNodeErrResponse
({
error
,
error
,
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
{
moduleLogo
:
plugin
?.
avatar
}
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
{
moduleLogo
:
workflowTool
?.
avatar
}
});
});
}
}
};
};
packages/service/core/workflow/dispatch/utils.ts
View file @
38f6f9dd
...
@@ -332,34 +332,29 @@ export const rewriteRuntimeWorkFlow = async ({
...
@@ -332,34 +332,29 @@ export const rewriteRuntimeWorkFlow = async ({
if
(
!
app
)
continue
;
if
(
!
app
)
continue
;
const
toolList
=
await
getMCPChildren
(
app
);
const
toolList
=
await
getMCPChildren
(
app
);
// mcpToolsetVal.toolId-旧版 MCP
// mcpToolsetVal.toolId: 旧版 MCP
const
toolSetId
=
mcpToolsetVal
.
toolId
??
toolSetNode
.
pluginId
;
const
toolSetId
=
mcpToolsetVal
.
toolId
||
toolSetNode
.
pluginId
;
toolList
.
forEach
((
tool
,
index
)
=>
{
toolList
.
forEach
((
tool
,
index
)
=>
{
const
newToolNode
=
getMCPToolRuntimeNode
({
const
newToolNode
=
getMCPToolRuntimeNode
({
nodeId
:
`
${
toolSetNode
.
nodeId
}${
index
}
`
,
nodeId
:
`
${
toolSetNode
.
nodeId
}${
index
}
`
,
toolSetId
,
toolSetId
,
toolsetName
:
toolSetNode
.
name
,
avatar
:
toolSetNode
.
avatar
,
avatar
:
toolSetNode
.
avatar
,
tool
:
{
tool
...
tool
,
name
:
`
${
toolSetNode
.
name
}
/
${
tool
.
name
}
`
}
});
});
nodes
.
push
(
newToolNode
);
nodes
.
push
(
newToolNode
);
pushEdges
(
newToolNode
.
nodeId
);
pushEdges
(
newToolNode
.
nodeId
);
});
});
}
else
if
(
httpToolsetVal
)
{
}
else
if
(
httpToolsetVal
)
{
httpToolsetVal
.
toolList
.
forEach
((
tool
:
HttpToolConfigType
,
index
:
number
)
=>
{
httpToolsetVal
.
toolList
.
forEach
((
tool
:
HttpToolConfigType
,
index
:
number
)
=>
{
const
newToolNode
=
getHTTPToolRuntimeNode
({
const
newToolNode
=
getHTTPToolRuntimeNode
({
tool
:
{
tool
,
...
tool
,
name
:
`
${
toolSetNode
.
name
}
/
${
tool
.
name
}
`
},
nodeId
:
`
${
toolSetNode
.
nodeId
}${
index
}
`
,
nodeId
:
`
${
toolSetNode
.
nodeId
}${
index
}
`
,
avatar
:
toolSetNode
.
avatar
,
avatar
:
toolSetNode
.
avatar
,
toolSetId
:
toolSetNode
.
pluginId
!
toolSetId
:
toolSetNode
.
pluginId
!
,
toolsetName
:
toolSetNode
.
name
});
});
nodes
.
push
(
newToolNode
);
nodes
.
push
(
newToolNode
);
pushEdges
(
newToolNode
.
nodeId
);
pushEdges
(
newToolNode
.
nodeId
);
});
});
...
...
packages/service/support/permission/app/auth.ts
View file @
38f6f9dd
...
@@ -15,12 +15,11 @@ import { type PermissionValueType } from '@fastgpt/global/support/permission/typ
...
@@ -15,12 +15,11 @@ import { type PermissionValueType } from '@fastgpt/global/support/permission/typ
import
{
AppFolderTypeList
,
AppTypeEnum
}
from
'@fastgpt/global/core/app/constants'
;
import
{
AppFolderTypeList
,
AppTypeEnum
}
from
'@fastgpt/global/core/app/constants'
;
import
{
type
ParentIdType
}
from
'@fastgpt/global/common/parentFolder/type'
;
import
{
type
ParentIdType
}
from
'@fastgpt/global/common/parentFolder/type'
;
import
{
type
AuthModeType
,
type
AuthResponseType
}
from
'../type'
;
import
{
type
AuthModeType
,
type
AuthResponseType
}
from
'../type'
;
import
{
splitCombineToolId
}
from
'@fastgpt/global/core/app/tool/utils'
;
import
{
AppReadChatLogPerVal
}
from
'@fastgpt/global/support/permission/app/constant'
;
import
{
AppReadChatLogPerVal
}
from
'@fastgpt/global/support/permission/app/constant'
;
import
{
parseHeaderCert
}
from
'../auth/common'
;
import
{
parseHeaderCert
}
from
'../auth/common'
;
import
{
sumPer
}
from
'@fastgpt/global/support/permission/utils'
;
import
{
sumPer
}
from
'@fastgpt/global/support/permission/utils'
;
export
const
auth
Plugin
ByTmbId
=
async
({
export
const
auth
WorkflowTool
ByTmbId
=
async
({
tmbId
,
tmbId
,
appId
,
appId
,
per
per
...
@@ -29,16 +28,12 @@ export const authPluginByTmbId = async ({
...
@@ -29,16 +28,12 @@ export const authPluginByTmbId = async ({
appId
:
string
;
appId
:
string
;
per
:
PermissionValueType
;
per
:
PermissionValueType
;
})
=>
{
})
=>
{
const
{
authAppId
}
=
splitCombineToolId
(
appId
);
if
(
authAppId
)
{
const
{
app
}
=
await
authAppByTmbId
({
const
{
app
}
=
await
authAppByTmbId
({
appId
:
authA
ppId
,
a
ppId
,
tmbId
,
tmbId
,
per
per
});
});
return
app
;
return
app
;
}
};
};
export
const
authAppByTmbId
=
async
({
export
const
authAppByTmbId
=
async
({
...
...
packages/web/i18n/en/common.json
View file @
38f6f9dd
...
@@ -177,7 +177,7 @@
...
@@ -177,7 +177,7 @@
"code_error.outlink_error.invalid_link"
:
"Invalid Share Link"
,
"code_error.outlink_error.invalid_link"
:
"Invalid Share Link"
,
"code_error.outlink_error.link_not_exist"
:
"Share Link Does Not Exist"
,
"code_error.outlink_error.link_not_exist"
:
"Share Link Does Not Exist"
,
"code_error.outlink_error.un_auth_user"
:
"Identity Verification Failed"
,
"code_error.outlink_error.un_auth_user"
:
"Identity Verification Failed"
,
"
code_error.plugin_error.
not_exist"
:
"Tool deleted"
,
"
error.tool_
not_exist"
:
"Tool deleted"
,
"code_error.plugin_error.un_auth"
:
"No permission to operate the tool"
,
"code_error.plugin_error.un_auth"
:
"No permission to operate the tool"
,
"code_error.system_error.community_version_num_limit"
:
"Exceeded Open Source Version Limit, Please Upgrade to Commercial Version: https://fastgpt.io"
,
"code_error.system_error.community_version_num_limit"
:
"Exceeded Open Source Version Limit, Please Upgrade to Commercial Version: https://fastgpt.io"
,
"code_error.system_error.license_app_amount_limit"
:
"Exceed the maximum number of applications in the system"
,
"code_error.system_error.license_app_amount_limit"
:
"Exceed the maximum number of applications in the system"
,
...
...
packages/web/i18n/zh-CN/common.json
View file @
38f6f9dd
...
@@ -177,7 +177,7 @@
...
@@ -177,7 +177,7 @@
"code_error.outlink_error.invalid_link"
:
"分享链接无效"
,
"code_error.outlink_error.invalid_link"
:
"分享链接无效"
,
"code_error.outlink_error.link_not_exist"
:
"分享链接不存在"
,
"code_error.outlink_error.link_not_exist"
:
"分享链接不存在"
,
"code_error.outlink_error.un_auth_user"
:
"身份校验失败"
,
"code_error.outlink_error.un_auth_user"
:
"身份校验失败"
,
"
code_error.plugin_error.
not_exist"
:
"工具已删除"
,
"
error.tool_
not_exist"
:
"工具已删除"
,
"code_error.plugin_error.un_auth"
:
"无权操作该工具"
,
"code_error.plugin_error.un_auth"
:
"无权操作该工具"
,
"code_error.system_error.community_version_num_limit"
:
"超出社区版数量限制,请升级商业版: https://fastgpt.in"
,
"code_error.system_error.community_version_num_limit"
:
"超出社区版数量限制,请升级商业版: https://fastgpt.in"
,
"code_error.system_error.license_app_amount_limit"
:
"超出系统最大应用数量"
,
"code_error.system_error.license_app_amount_limit"
:
"超出系统最大应用数量"
,
...
...
packages/web/i18n/zh-Hant/common.json
View file @
38f6f9dd
...
@@ -176,7 +176,7 @@
...
@@ -176,7 +176,7 @@
"code_error.outlink_error.invalid_link"
:
"分享連結無效"
,
"code_error.outlink_error.invalid_link"
:
"分享連結無效"
,
"code_error.outlink_error.link_not_exist"
:
"分享連結不存在"
,
"code_error.outlink_error.link_not_exist"
:
"分享連結不存在"
,
"code_error.outlink_error.un_auth_user"
:
"身份驗證失敗"
,
"code_error.outlink_error.un_auth_user"
:
"身份驗證失敗"
,
"
code_error.plugin_error.
not_exist"
:
"工具已刪除"
,
"
error.tool_
not_exist"
:
"工具已刪除"
,
"code_error.plugin_error.un_auth"
:
"無權操作該工具"
,
"code_error.plugin_error.un_auth"
:
"無權操作該工具"
,
"code_error.system_error.community_version_num_limit"
:
"超出開源版數量限制,請升級商業版:https://fastgpt.io"
,
"code_error.system_error.community_version_num_limit"
:
"超出開源版數量限制,請升級商業版:https://fastgpt.io"
,
"code_error.system_error.license_app_amount_limit"
:
"超出系統最大應用數量"
,
"code_error.system_error.license_app_amount_limit"
:
"超出系統最大應用數量"
,
...
...
projects/app/package.json
View file @
38f6f9dd
{
{
"name"
:
"
app
"
,
"name"
:
"
app
"
,
"version"
:
"4.14.8"
,
"version"
:
"4.14.8
.1
"
,
"private"
:
false
,
"private"
:
false
,
"scripts"
:
{
"scripts"
:
{
"dev"
:
"npm run build:workers && next dev"
,
"dev"
:
"npm run build:workers && next dev"
,
...
...
projects/app/src/pages/api/core/app/mcpTools/create.ts
View file @
38f6f9dd
...
@@ -55,8 +55,7 @@ async function handler(
...
@@ -55,8 +55,7 @@ async function handler(
toolList
,
toolList
,
name
,
name
,
avatar
,
avatar
,
headerSecret
:
formatedHeaderAuth
,
headerSecret
:
formatedHeaderAuth
toolId
:
''
})
})
],
],
session
session
...
...
projects/app/src/pages/api/core/app/mcpTools/update.ts
View file @
38f6f9dd
...
@@ -28,8 +28,7 @@ async function handler(req: ApiRequestProps<UpdateMcpToolsBodyType>, res: ApiRes
...
@@ -28,8 +28,7 @@ async function handler(req: ApiRequestProps<UpdateMcpToolsBodyType>, res: ApiRes
toolList
,
toolList
,
headerSecret
:
formatedHeaderAuth
,
headerSecret
:
formatedHeaderAuth
,
name
:
app
.
name
,
name
:
app
.
name
,
avatar
:
app
.
avatar
,
avatar
:
app
.
avatar
toolId
:
''
});
});
await
mongoSessionRun
(
async
(
session
)
=>
{
await
mongoSessionRun
(
async
(
session
)
=>
{
...
...
projects/app/src/pages/api/core/app/tool/getVersionList.ts
View file @
38f6f9dd
...
@@ -39,7 +39,7 @@ async function handler(
...
@@ -39,7 +39,7 @@ async function handler(
// System tool plugin
// System tool plugin
if
(
source
===
AppToolSourceEnum
.
systemTool
)
{
if
(
source
===
AppToolSourceEnum
.
systemTool
)
{
const
item
=
await
getSystemToolByIdAndVersionId
(
formatP
luginId
);
const
item
=
await
getSystemToolByIdAndVersionId
(
p
luginId
);
return
{
return
{
total
:
0
,
total
:
0
,
...
...
test/cases/global/core/app/tool/httpTool/utils.test.ts
View file @
38f6f9dd
...
@@ -103,14 +103,15 @@ describe('httpTool utils', () => {
...
@@ -103,14 +103,15 @@ describe('httpTool utils', () => {
const
result
=
getHTTPToolRuntimeNode
({
const
result
=
getHTTPToolRuntimeNode
({
tool
,
tool
,
nodeId
:
'node-123'
,
nodeId
:
'node-123'
,
toolSetId
:
'toolset-456'
toolSetId
:
'toolset-456'
,
toolsetName
:
'toolsetName'
});
});
expect
(
result
.
nodeId
).
toBe
(
'node-123'
);
expect
(
result
.
nodeId
).
toBe
(
'node-123'
);
expect
(
result
.
flowNodeType
).
toBe
(
FlowNodeTypeEnum
.
tool
);
expect
(
result
.
flowNodeType
).
toBe
(
FlowNodeTypeEnum
.
tool
);
expect
(
result
.
avatar
).
toBe
(
'core/app/type/httpToolsFill'
);
expect
(
result
.
avatar
).
toBe
(
'core/app/type/httpToolsFill'
);
expect
(
result
.
intro
).
toBe
(
'Search for items'
);
expect
(
result
.
intro
).
toBe
(
'Search for items'
);
expect
(
result
.
name
).
toBe
(
'searchTool'
);
expect
(
result
.
name
).
toBe
(
'
toolsetName/
searchTool'
);
expect
(
result
.
toolConfig
?.
httpTool
?.
toolId
).
toBe
(
expect
(
result
.
toolConfig
?.
httpTool
?.
toolId
).
toBe
(
`
${
AppToolSourceEnum
.
http
}
-toolset-456/searchTool`
`
${
AppToolSourceEnum
.
http
}
-toolset-456/searchTool`
);
);
...
@@ -128,7 +129,8 @@ describe('httpTool utils', () => {
...
@@ -128,7 +129,8 @@ describe('httpTool utils', () => {
tool
,
tool
,
nodeId
:
'node-789'
,
nodeId
:
'node-789'
,
avatar
:
'custom-icon'
,
avatar
:
'custom-icon'
,
toolSetId
:
'toolset-abc'
toolSetId
:
'toolset-abc'
,
toolsetName
:
'toolsetName'
});
});
expect
(
result
.
avatar
).
toBe
(
'custom-icon'
);
expect
(
result
.
avatar
).
toBe
(
'custom-icon'
);
...
@@ -145,7 +147,8 @@ describe('httpTool utils', () => {
...
@@ -145,7 +147,8 @@ describe('httpTool utils', () => {
const
result
=
getHTTPToolRuntimeNode
({
const
result
=
getHTTPToolRuntimeNode
({
tool
,
tool
,
nodeId
:
'node-001'
,
nodeId
:
'node-001'
,
toolSetId
:
'toolset-002'
toolSetId
:
'toolset-002'
,
toolsetName
:
'toolsetName'
});
});
const
rawResponseOutput
=
result
.
outputs
.
find
((
o
)
=>
o
.
key
===
NodeOutputKeyEnum
.
rawResponse
);
const
rawResponseOutput
=
result
.
outputs
.
find
((
o
)
=>
o
.
key
===
NodeOutputKeyEnum
.
rawResponse
);
...
...
test/cases/global/core/app/tool/mcpTool/utils.test.ts
View file @
38f6f9dd
...
@@ -28,8 +28,7 @@ describe('mcpTool utils', () => {
...
@@ -28,8 +28,7 @@ describe('mcpTool utils', () => {
const
result
=
getMCPToolSetRuntimeNode
({
const
result
=
getMCPToolSetRuntimeNode
({
url
:
'https://mcp.example.com/api'
,
url
:
'https://mcp.example.com/api'
,
toolList
,
toolList
toolId
:
'mcp-tool-123'
});
});
expect
(
result
.
flowNodeType
).
toBe
(
FlowNodeTypeEnum
.
toolSet
);
expect
(
result
.
flowNodeType
).
toBe
(
FlowNodeTypeEnum
.
toolSet
);
...
@@ -40,7 +39,6 @@ describe('mcpTool utils', () => {
...
@@ -40,7 +39,6 @@ describe('mcpTool utils', () => {
expect
(
result
.
nodeId
).
toHaveLength
(
16
);
expect
(
result
.
nodeId
).
toHaveLength
(
16
);
expect
(
result
.
toolConfig
?.
mcpToolSet
?.
url
).
toBe
(
'https://mcp.example.com/api'
);
expect
(
result
.
toolConfig
?.
mcpToolSet
?.
url
).
toBe
(
'https://mcp.example.com/api'
);
expect
(
result
.
toolConfig
?.
mcpToolSet
?.
toolList
).
toEqual
(
toolList
);
expect
(
result
.
toolConfig
?.
mcpToolSet
?.
toolList
).
toEqual
(
toolList
);
expect
(
result
.
toolConfig
?.
mcpToolSet
?.
toolId
).
toBe
(
'mcp-tool-123'
);
});
});
it
(
'should create runtime node with all optional params'
,
()
=>
{
it
(
'should create runtime node with all optional params'
,
()
=>
{
...
@@ -49,7 +47,6 @@ describe('mcpTool utils', () => {
...
@@ -49,7 +47,6 @@ describe('mcpTool utils', () => {
const
result
=
getMCPToolSetRuntimeNode
({
const
result
=
getMCPToolSetRuntimeNode
({
url
:
'https://mcp.example.com/api'
,
url
:
'https://mcp.example.com/api'
,
toolList
,
toolList
,
toolId
:
'mcp-tool-456'
,
name
:
'My MCP Tools'
,
name
:
'My MCP Tools'
,
avatar
:
'custom-mcp-avatar'
,
avatar
:
'custom-mcp-avatar'
,
headerSecret
:
{
id
:
'secret-1'
,
key
:
'Authorization'
}
headerSecret
:
{
id
:
'secret-1'
,
key
:
'Authorization'
}
...
@@ -81,14 +78,15 @@ describe('mcpTool utils', () => {
...
@@ -81,14 +78,15 @@ describe('mcpTool utils', () => {
const
result
=
getMCPToolRuntimeNode
({
const
result
=
getMCPToolRuntimeNode
({
tool
,
tool
,
nodeId
:
'node-123'
,
nodeId
:
'node-123'
,
toolSetId
:
'toolset-456'
toolSetId
:
'toolset-456'
,
toolsetName
:
'toolsetName'
});
});
expect
(
result
.
nodeId
).
toBe
(
'node-123'
);
expect
(
result
.
nodeId
).
toBe
(
'node-123'
);
expect
(
result
.
flowNodeType
).
toBe
(
FlowNodeTypeEnum
.
tool
);
expect
(
result
.
flowNodeType
).
toBe
(
FlowNodeTypeEnum
.
tool
);
expect
(
result
.
avatar
).
toBe
(
'core/app/type/mcpToolsFill'
);
expect
(
result
.
avatar
).
toBe
(
'core/app/type/mcpToolsFill'
);
expect
(
result
.
intro
).
toBe
(
'Search for information'
);
expect
(
result
.
intro
).
toBe
(
'Search for information'
);
expect
(
result
.
name
).
toBe
(
'searchTool'
);
expect
(
result
.
name
).
toBe
(
'
toolsetName/
searchTool'
);
expect
(
result
.
toolConfig
?.
mcpTool
?.
toolId
).
toBe
(
expect
(
result
.
toolConfig
?.
mcpTool
?.
toolId
).
toBe
(
`
${
AppToolSourceEnum
.
mcp
}
-toolset-456/searchTool`
`
${
AppToolSourceEnum
.
mcp
}
-toolset-456/searchTool`
);
);
...
@@ -105,7 +103,8 @@ describe('mcpTool utils', () => {
...
@@ -105,7 +103,8 @@ describe('mcpTool utils', () => {
tool
,
tool
,
nodeId
:
'node-789'
,
nodeId
:
'node-789'
,
avatar
:
'custom-icon'
,
avatar
:
'custom-icon'
,
toolSetId
:
'toolset-abc'
toolSetId
:
'toolset-abc'
,
toolsetName
:
'toolsetName'
});
});
expect
(
result
.
avatar
).
toBe
(
'custom-icon'
);
expect
(
result
.
avatar
).
toBe
(
'custom-icon'
);
...
@@ -121,7 +120,8 @@ describe('mcpTool utils', () => {
...
@@ -121,7 +120,8 @@ describe('mcpTool utils', () => {
const
result
=
getMCPToolRuntimeNode
({
const
result
=
getMCPToolRuntimeNode
({
tool
,
tool
,
nodeId
:
'node-001'
,
nodeId
:
'node-001'
,
toolSetId
:
'toolset-002'
toolSetId
:
'toolset-002'
,
toolsetName
:
'toolsetName'
});
});
expect
(
result
.
outputs
).
toHaveLength
(
1
);
expect
(
result
.
outputs
).
toHaveLength
(
1
);
...
@@ -142,7 +142,8 @@ describe('mcpTool utils', () => {
...
@@ -142,7 +142,8 @@ describe('mcpTool utils', () => {
const
result
=
getMCPToolRuntimeNode
({
const
result
=
getMCPToolRuntimeNode
({
tool
,
tool
,
nodeId
:
'node-test'
,
nodeId
:
'node-test'
,
toolSetId
:
'parent-123'
toolSetId
:
'parent-123'
,
toolsetName
:
'toolsetName'
});
});
expect
(
result
.
toolConfig
?.
mcpTool
?.
toolId
).
toBe
(
'mcp-parent-123/myTool'
);
expect
(
result
.
toolConfig
?.
mcpTool
?.
toolId
).
toBe
(
'mcp-parent-123/myTool'
);
...
...
test/cases/global/core/app/tool/utils.test.ts
View file @
38f6f9dd
...
@@ -25,7 +25,6 @@ describe('splitCombineToolId', () => {
...
@@ -25,7 +25,6 @@ describe('splitCombineToolId', () => {
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
personal
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
personal
);
expect
(
result
.
pluginId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
pluginId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
});
});
});
});
...
@@ -34,14 +33,14 @@ describe('splitCombineToolId', () => {
...
@@ -34,14 +33,14 @@ describe('splitCombineToolId', () => {
const
result
=
splitCombineToolId
(
'commercial-507f1f77bcf86cd799439011'
);
const
result
=
splitCombineToolId
(
'commercial-507f1f77bcf86cd799439011'
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
commercial
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
commercial
);
expect
(
result
.
pluginId
).
toBe
(
'
commercial-
507f1f77bcf86cd799439011'
);
expect
(
result
.
pluginId
).
toBe
(
'507f1f77bcf86cd799439011'
);
});
});
it
(
'should convert commercial-dalle3 to systemTool'
,
()
=>
{
it
(
'should convert commercial-dalle3 to systemTool
(Adapt)
'
,
()
=>
{
const
result
=
splitCombineToolId
(
'commercial-dalle3'
);
const
result
=
splitCombineToolId
(
'commercial-dalle3'
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
systemTool
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
systemTool
);
expect
(
result
.
pluginId
).
toBe
(
'
systemTool-
dalle3'
);
expect
(
result
.
pluginId
).
toBe
(
'dalle3'
);
});
});
});
});
...
@@ -50,14 +49,14 @@ describe('splitCombineToolId', () => {
...
@@ -50,14 +49,14 @@ describe('splitCombineToolId', () => {
const
result
=
splitCombineToolId
(
'systemTool-websearch'
);
const
result
=
splitCombineToolId
(
'systemTool-websearch'
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
systemTool
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
systemTool
);
expect
(
result
.
pluginId
).
toBe
(
'
systemTool-
websearch'
);
expect
(
result
.
pluginId
).
toBe
(
'websearch'
);
});
});
it
(
'should handle systemTool with complex id'
,
()
=>
{
it
(
'should handle systemTool with complex id'
,
()
=>
{
const
result
=
splitCombineToolId
(
'systemTool-code-interpreter'
);
const
result
=
splitCombineToolId
(
'systemTool-code-interpreter'
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
systemTool
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
systemTool
);
expect
(
result
.
pluginId
).
toBe
(
'
systemTool-
code-interpreter'
);
expect
(
result
.
pluginId
).
toBe
(
'code-interpreter'
);
});
});
});
});
...
@@ -85,7 +84,7 @@ describe('splitCombineToolId', () => {
...
@@ -85,7 +84,7 @@ describe('splitCombineToolId', () => {
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
http
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
http
);
expect
(
result
.
pluginId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
pluginId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
parent
Id
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
authApp
Id
).
toBe
(
'507f1f77bcf86cd799439011'
);
});
});
it
(
'should parse http-parentId/toolName format correctly'
,
()
=>
{
it
(
'should parse http-parentId/toolName format correctly'
,
()
=>
{
...
@@ -93,7 +92,6 @@ describe('splitCombineToolId', () => {
...
@@ -93,7 +92,6 @@ describe('splitCombineToolId', () => {
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
http
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
http
);
expect
(
result
.
pluginId
).
toBe
(
'507f1f77bcf86cd799439011/apiTool'
);
expect
(
result
.
pluginId
).
toBe
(
'507f1f77bcf86cd799439011/apiTool'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
});
});
});
});
...
@@ -102,13 +100,13 @@ describe('splitCombineToolId', () => {
...
@@ -102,13 +100,13 @@ describe('splitCombineToolId', () => {
const
result
=
splitCombineToolId
(
'community-oldPlugin'
);
const
result
=
splitCombineToolId
(
'community-oldPlugin'
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
systemTool
);
expect
(
result
.
source
).
toBe
(
AppToolSourceEnum
.
systemTool
);
expect
(
result
.
pluginId
).
toBe
(
'
systemTool-
oldPlugin'
);
expect
(
result
.
pluginId
).
toBe
(
'oldPlugin'
);
});
});
});
});
describe
(
'error handling'
,
()
=>
{
describe
(
'error handling'
,
()
=>
{
it
(
'should throw error when pluginId is empty after split'
,
()
=>
{
it
(
'should throw error when pluginId is empty after split'
,
()
=>
{
expect
(()
=>
splitCombineToolId
(
'commercial-'
)).
toThrow
(
'
plugin
Id not found'
);
expect
(()
=>
splitCombineToolId
(
'commercial-'
)).
toThrow
(
'
tool
Id not found'
);
});
});
});
});
});
});
...
@@ -121,7 +119,7 @@ describe('getToolRawId', () => {
...
@@ -121,7 +119,7 @@ describe('getToolRawId', () => {
it
(
'should return pluginId for commercial tool'
,
()
=>
{
it
(
'should return pluginId for commercial tool'
,
()
=>
{
const
result
=
getToolRawId
(
'commercial-507f1f77bcf86cd799439011'
);
const
result
=
getToolRawId
(
'commercial-507f1f77bcf86cd799439011'
);
expect
(
result
).
toBe
(
'
commercial-
507f1f77bcf86cd799439011'
);
expect
(
result
).
toBe
(
'507f1f77bcf86cd799439011'
);
});
});
it
(
'should return parentId for mcp tool with toolName'
,
()
=>
{
it
(
'should return parentId for mcp tool with toolName'
,
()
=>
{
...
@@ -136,7 +134,7 @@ describe('getToolRawId', () => {
...
@@ -136,7 +134,7 @@ describe('getToolRawId', () => {
it
(
'should handle systemTool correctly'
,
()
=>
{
it
(
'should handle systemTool correctly'
,
()
=>
{
const
result
=
getToolRawId
(
'systemTool-websearch'
);
const
result
=
getToolRawId
(
'systemTool-websearch'
);
expect
(
result
).
toBe
(
'
systemTool-
websearch'
);
expect
(
result
).
toBe
(
'websearch'
);
});
});
it
(
'should handle personal tool with prefix'
,
()
=>
{
it
(
'should handle personal tool with prefix'
,
()
=>
{
...
@@ -146,6 +144,6 @@ describe('getToolRawId', () => {
...
@@ -146,6 +144,6 @@ describe('getToolRawId', () => {
it
(
'should handle converted community tool'
,
()
=>
{
it
(
'should handle converted community tool'
,
()
=>
{
const
result
=
getToolRawId
(
'community-oldPlugin'
);
const
result
=
getToolRawId
(
'community-oldPlugin'
);
expect
(
result
).
toBe
(
'
systemTool-
oldPlugin'
);
expect
(
result
).
toBe
(
'oldPlugin'
);
});
});
});
});
test/cases/service/core/workflow/dispatch/tools/runTool.test.ts
0 → 100644
View file @
38f6f9dd
import
{
describe
,
it
,
expect
}
from
'vitest'
;
import
{
parseToolId
}
from
'@fastgpt/service/core/workflow/dispatch/child/runTool'
;
describe
(
'parseToolId'
,
()
=>
{
describe
(
'新版格式: source-appId/toolName'
,
()
=>
{
it
(
'should parse mcp tool format correctly'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/apiTool'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'apiTool'
);
});
it
(
'should parse http tool format correctly'
,
()
=>
{
const
result
=
parseToolId
(
'http-507f1f77bcf86cd799439011/weatherAPI'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'weatherAPI'
);
});
it
(
'should handle tool names with special characters'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/api-tool_v2'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'api-tool_v2'
);
});
it
(
'should handle tool names with numbers'
,
()
=>
{
const
result
=
parseToolId
(
'http-507f1f77bcf86cd799439011/tool123'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'tool123'
);
});
});
describe
(
'旧版格式: source-appId/toolsetName/toolName'
,
()
=>
{
it
(
'should parse old mcp format correctly'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/toolset/apiTool'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'apiTool'
);
});
it
(
'should parse old http format correctly'
,
()
=>
{
const
result
=
parseToolId
(
'http-507f1f77bcf86cd799439011/MyToolset/weatherAPI'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'weatherAPI'
);
});
it
(
'should ignore toolset name in old format'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/ignoredToolset/actualTool'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'actualTool'
);
// toolsetName 应该被忽略
});
it
(
'should handle toolset names with special characters'
,
()
=>
{
const
result
=
parseToolId
(
'http-507f1f77bcf86cd799439011/tool-set_v1/myTool'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'myTool'
);
});
});
describe
(
'边界情况'
,
()
=>
{
it
(
'should handle appId with hyphens'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f-1f77-bcf8-6cd7-99439011/tool'
);
expect
(
result
.
parentId
).
toBe
(
'507f-1f77-bcf8-6cd7-99439011'
);
expect
(
result
.
toolName
).
toBe
(
'tool'
);
});
it
(
'should handle multiple hyphens in source prefix'
,
()
=>
{
const
result
=
parseToolId
(
'custom-source-507f1f77bcf86cd799439011/tool'
);
expect
(
result
.
parentId
).
toBe
(
'source-507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'tool'
);
});
it
(
'should handle tool names with slashes in old format'
,
()
=>
{
// 注意: split('/') 只会分割成三个部分,所以第三个部分是 'tool'
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/toolset/tool/extra'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
// 实际上 split('/') 会得到 ['507f1f77bcf86cd799439011', 'toolset', 'tool/extra']
// 但由于解构赋值,legacyToolName 会是 'tool/extra'
// 等等,让我重新理解代码逻辑...
// formatId.split('/') 会得到 ['507f1f77bcf86cd799439011', 'toolset', 'tool', 'extra']
// 解构赋值只取前三个: parentId='507f1f77bcf86cd799439011', toolsetNameOrToolName='toolset', legacyToolName='tool'
// 所以 toolName 应该是 'tool',而不是 'tool/extra'
expect
(
result
.
toolName
).
toBe
(
'tool'
);
});
it
(
'should handle empty tool name'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
''
);
});
it
(
'should handle empty toolset and tool name in old format'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011//'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
''
);
});
});
describe
(
'向后兼容性'
,
()
=>
{
it
(
'should correctly identify new format vs old format'
,
()
=>
{
// 新版格式: 只有两个部分(appId 和 toolName)
const
newFormat
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/tool'
);
expect
(
newFormat
.
toolName
).
toBe
(
'tool'
);
// 旧版格式: 有三个部分(appId, toolsetName, toolName)
const
oldFormat
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/toolset/tool'
);
expect
(
oldFormat
.
toolName
).
toBe
(
'tool'
);
// 两者的 toolName 应该相同
expect
(
newFormat
.
toolName
).
toBe
(
oldFormat
.
toolName
);
});
it
(
'should handle migration from old to new format'
,
()
=>
{
const
oldId
=
'mcp-507f1f77bcf86cd799439011/MyToolset/weatherAPI'
;
const
newId
=
'mcp-507f1f77bcf86cd799439011/weatherAPI'
;
const
oldResult
=
parseToolId
(
oldId
);
const
newResult
=
parseToolId
(
newId
);
// 两种格式应该解析出相同的 parentId 和 toolName
expect
(
oldResult
.
parentId
).
toBe
(
newResult
.
parentId
);
expect
(
oldResult
.
toolName
).
toBe
(
newResult
.
toolName
);
});
});
describe
(
'真实场景测试'
,
()
=>
{
it
(
'should parse real MCP tool ID'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-65f8a9b2c3d4e5f6a7b8c9d0/filesystem/readFile'
);
expect
(
result
.
parentId
).
toBe
(
'65f8a9b2c3d4e5f6a7b8c9d0'
);
expect
(
result
.
toolName
).
toBe
(
'readFile'
);
});
it
(
'should parse real HTTP tool ID'
,
()
=>
{
const
result
=
parseToolId
(
'http-65f8a9b2c3d4e5f6a7b8c9d0/WeatherAPI'
);
expect
(
result
.
parentId
).
toBe
(
'65f8a9b2c3d4e5f6a7b8c9d0'
);
expect
(
result
.
toolName
).
toBe
(
'WeatherAPI'
);
});
it
(
'should handle Chinese tool names'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011/天气查询'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'天气查询'
);
});
it
(
'should handle tool names with spaces'
,
()
=>
{
const
result
=
parseToolId
(
'http-507f1f77bcf86cd799439011/Weather API'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBe
(
'Weather API'
);
});
});
describe
(
'性能测试'
,
()
=>
{
it
(
'should parse tool IDs efficiently'
,
()
=>
{
const
iterations
=
10000
;
const
start
=
Date
.
now
();
for
(
let
i
=
0
;
i
<
iterations
;
i
++
)
{
parseToolId
(
'mcp-507f1f77bcf86cd799439011/toolset/tool'
);
}
const
duration
=
Date
.
now
()
-
start
;
console
.
log
(
`Parsed
${
iterations
}
tool IDs in
${
duration
}
ms`
);
// 性能检查: 10000 次解析应该在 100ms 内完成
expect
(
duration
).
toBeLessThan
(
100
);
});
it
(
'should handle batch parsing'
,
()
=>
{
const
toolIds
=
[
'mcp-507f1f77bcf86cd799439011/tool1'
,
'http-507f1f77bcf86cd799439011/tool2'
,
'mcp-507f1f77bcf86cd799439011/toolset/tool3'
,
'http-507f1f77bcf86cd799439011/toolset/tool4'
];
const
results
=
toolIds
.
map
((
id
)
=>
parseToolId
(
id
));
expect
(
results
).
toHaveLength
(
4
);
expect
(
results
[
0
].
toolName
).
toBe
(
'tool1'
);
expect
(
results
[
1
].
toolName
).
toBe
(
'tool2'
);
expect
(
results
[
2
].
toolName
).
toBe
(
'tool3'
);
expect
(
results
[
3
].
toolName
).
toBe
(
'tool4'
);
});
});
describe
(
'错误处理'
,
()
=>
{
it
(
'should handle missing slash'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-507f1f77bcf86cd799439011'
);
expect
(
result
.
parentId
).
toBe
(
'507f1f77bcf86cd799439011'
);
expect
(
result
.
toolName
).
toBeUndefined
();
});
it
(
'should handle only source prefix'
,
()
=>
{
const
result
=
parseToolId
(
'mcp-'
);
expect
(
result
.
parentId
).
toBe
(
''
);
expect
(
result
.
toolName
).
toBeUndefined
();
});
it
(
'should handle malformed ID gracefully'
,
()
=>
{
// 虽然这些是无效的 ID,但函数应该不会崩溃
expect
(()
=>
parseToolId
(
'invalid'
)).
not
.
toThrow
();
expect
(()
=>
parseToolId
(
''
)).
not
.
toThrow
();
expect
(()
=>
parseToolId
(
'/'
)).
not
.
toThrow
();
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment