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
9c60f089
authored
Jul 02, 2026
by
Finley Ge
Committed by
GitHub
Jul 02, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(system-tool): omit null json schema fields (#7239)
parent
85fbe9dc
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
125 additions
and
19 deletions
+125
-19
packages/global/core/app/tool/systemTool/type/base.ts
+15
-5
packages/global/test/core/app/tool/systemTool/type.test.ts
+46
-1
packages/service/core/app/tool/systemTool/systemTool.repo.ts
+18
-13
packages/service/test/core/app/tool/systemTool/systemTool.repo.test.ts
+46
-0
No files found.
packages/global/core/app/tool/systemTool/type/base.ts
View file @
9c60f089
...
...
@@ -5,6 +5,16 @@ import { PluginPermissionEnumSchema } from '../../../../../sdk/fastgpt-plugin';
import
{
SystemToolSystemSecretStatusEnum
}
from
'../constants'
;
import
{
JSONSchemaInputTypeSchema
,
JSONSchemaOutputTypeSchema
}
from
'../../../jsonschema'
;
const
OptionalJSONSchemaInputTypeSchema
=
z
.
preprocess
(
(
value
)
=>
(
value
===
null
?
undefined
:
value
),
JSONSchemaInputTypeSchema
.
optional
()
);
const
OptionalJSONSchemaOutputTypeSchema
=
z
.
preprocess
(
(
value
)
=>
(
value
===
null
?
undefined
:
value
),
JSONSchemaOutputTypeSchema
.
optional
()
);
// 系统工具最基础最通用的类型
export
const
SystemToolBaseSchema
=
z
.
object
({
id
:
z
.
string
(),
...
...
@@ -74,8 +84,8 @@ export const SystemToolChildDetailSchema = z.object({
icon
:
z
.
string
().
optional
(),
currentCost
:
z
.
number
().
meta
({
description
:
'当前使用的费用'
}),
systemKeyCost
:
z
.
number
().
meta
({
description
:
'系统密钥的费用'
}),
inputSchema
:
JSONSchemaInputTypeSchema
.
optional
()
,
outputSchema
:
JSONSchemaOutputTypeSchema
.
optional
()
inputSchema
:
OptionalJSONSchemaInputTypeSchema
,
outputSchema
:
OptionalJSONSchemaOutputTypeSchema
});
export
type
SystemToolChildDetailType
=
z
.
infer
<
typeof
SystemToolChildDetailSchema
>
;
...
...
@@ -85,9 +95,9 @@ export const SystemToolDetailSchema = z.object({
...
SystemToolListItemSchema
.
shape
,
children
:
z
.
array
(
SystemToolChildDetailSchema
).
optional
(),
inputSchema
:
JSONSchemaInputTypeSchema
.
optional
()
,
outputSchema
:
JSONSchemaOutputTypeSchema
.
optional
()
,
secretSchema
:
JSONSchemaInputTypeSchema
.
optional
()
,
inputSchema
:
OptionalJSONSchemaInputTypeSchema
,
outputSchema
:
OptionalJSONSchemaOutputTypeSchema
,
secretSchema
:
OptionalJSONSchemaInputTypeSchema
,
secretsVal
:
z
.
record
(
z
.
string
(),
z
.
any
()).
nullish
(),
isLatestVersion
:
z
.
boolean
().
optional
(),
associatedPluginId
:
z
.
string
().
optional
(),
...
...
packages/global/test/core/app/tool/systemTool/type.test.ts
View file @
9c60f089
import
{
describe
,
expect
,
it
}
from
'vitest'
;
import
{
AdminSystemToolDetailSchema
}
from
'@fastgpt/global/core/app/tool/systemTool/type'
;
import
{
AdminSystemToolDetailSchema
,
SystemToolDetailSchema
}
from
'@fastgpt/global/core/app/tool/systemTool/type'
;
import
{
PluginStatusEnum
}
from
'@fastgpt/global/core/plugin/type'
;
import
{
SystemToolSystemSecretStatusEnum
}
from
'@fastgpt/global/core/app/tool/systemTool/constants'
;
import
{
TeamToolDetailSchema
}
from
'@fastgpt/global/openapi/core/plugin/team/tool/api'
;
const
createAdminToolDetail
=
()
=>
({
id
:
'systemTool-null-schema'
,
...
...
@@ -67,3 +71,44 @@ describe('AdminSystemToolDetailSchema', () => {
expect
(
result
.
children
?.[
0
]).
not
.
toHaveProperty
(
'outputSchema'
);
});
});
describe
(
'SystemToolDetailSchema'
,
()
=>
{
it
(
'treats null input and output schemas as missing schema fields'
,
()
=>
{
const
result
=
SystemToolDetailSchema
.
parse
({
...
createAdminToolDetail
(),
inputSchema
:
null
,
outputSchema
:
null
,
secretSchema
:
null
});
expect
(
result
.
inputSchema
).
toBeUndefined
();
expect
(
result
.
outputSchema
).
toBeUndefined
();
expect
(
result
.
secretSchema
).
toBeUndefined
();
});
});
describe
(
'TeamToolDetailSchema'
,
()
=>
{
it
(
'accepts null tool schemas from legacy plugin definitions'
,
()
=>
{
const
result
=
TeamToolDetailSchema
.
parse
({
...
createAdminToolDetail
(),
inputSchema
:
null
,
outputSchema
:
null
,
children
:
[
{
id
:
'child'
,
name
:
'Child tool'
,
status
:
PluginStatusEnum
.
Normal
,
currentCost
:
0
,
systemKeyCost
:
0
,
inputSchema
:
null
,
outputSchema
:
null
}
]
});
expect
(
result
.
inputSchema
).
toBeUndefined
();
expect
(
result
.
outputSchema
).
toBeUndefined
();
expect
(
result
.
children
?.[
0
].
inputSchema
).
toBeUndefined
();
expect
(
result
.
children
?.[
0
].
outputSchema
).
toBeUndefined
();
});
});
packages/service/core/app/tool/systemTool/systemTool.repo.ts
View file @
9c60f089
...
...
@@ -128,6 +128,8 @@ const getPluginClientSource = ({
return
runtimeSource
||
'system'
;
};
const
normalizeOptionalJsonSchema
=
<
T
>
(
schema
:
T
|
null
|
undefined
)
=>
schema
??
undefined
;
const
getSystemToolConfigIds
=
(
pluginId
:
string
)
=>
{
const
systemToolPrefix
=
`
${
AppToolSourceEnum
.
systemTool
}
-`
;
const
commercialPrefix
=
`
${
AppToolSourceEnum
.
commercial
}
-`
;
...
...
@@ -421,6 +423,9 @@ export class SystemToolRepo {
const
children
=
tool
.
isToolset
?
tool
.
children
?.
map
((
item
)
=>
{
const
dbChild
=
getFirstSystemToolConfig
(
dbChildrenMap
,
`
${
pluginId
}
/
${
item
.
id
}
`
);
const
inputSchema
=
normalizeOptionalJsonSchema
(
item
.
inputSchema
);
const
outputSchema
=
normalizeOptionalJsonSchema
(
item
.
outputSchema
);
return
{
id
:
item
.
id
,
name
:
parseI18nString
(
item
.
name
,
lang
),
...
...
@@ -432,13 +437,20 @@ export class SystemToolRepo {
systemKeyCost
:
dbChild
?.
systemKeyCost
??
0
,
currentCost
:
dbChild
?.
currentCost
??
0
,
icon
:
item
.
icon
,
inputSchema
:
item
.
inputSchema
,
outputSchema
:
item
.
outputSchema
...(
inputSchema
!==
undefined
?
{
inputSchema
}
:
{})
,
...(
outputSchema
!==
undefined
?
{
outputSchema
}
:
{})
}
satisfies
SystemToolChildDetailType
;
})
:
undefined
;
const
secrets
=
jsonSchema2SecretInput
({
jsonSchema
:
tool
.
secretSchema
});
const
secretSchema
=
normalizeOptionalJsonSchema
(
tool
.
secretSchema
);
const
inputSchema
=
normalizeOptionalJsonSchema
(
childPluginId
?
child
!
.
inputSchema
:
tool
.
inputSchema
);
const
outputSchema
=
normalizeOptionalJsonSchema
(
childPluginId
?
child
!
.
outputSchema
:
tool
.
outputSchema
);
const
secrets
=
jsonSchema2SecretInput
({
jsonSchema
:
secretSchema
});
const
configuredSecretsVal
=
SystemToolCodec
.
getConfiguredSecretsVal
(
dbTool
);
const
hasSystemSecret
=
!!
configuredSecretsVal
;
...
...
@@ -483,17 +495,10 @@ export class SystemToolRepo {
hideTags
:
dbTool
?.
hideTags
??
[],
promoteTags
:
dbTool
?.
promoteTags
??
[],
pluginOrder
:
dbTool
?.
pluginOrder
,
secretSchema
:
tool
.
secretSchema
,
...(
secretSchema
!==
undefined
?
{
secretSchema
}
:
{})
,
isLatestVersion
:
tool
.
isLatestVersion
,
...(
childPluginId
?
{
inputSchema
:
child
!
.
inputSchema
,
outputSchema
:
child
!
.
outputSchema
}
:
{
inputSchema
:
tool
.
inputSchema
,
outputSchema
:
tool
.
outputSchema
}),
...(
inputSchema
!==
undefined
?
{
inputSchema
}
:
{}),
...(
outputSchema
!==
undefined
?
{
outputSchema
}
:
{}),
permissions
:
tool
.
permission
};
...
...
packages/service/test/core/app/tool/systemTool/systemTool.repo.test.ts
View file @
9c60f089
...
...
@@ -408,6 +408,52 @@ describe('SystemToolRepo.getSystemToolDetail', () => {
expect
(
tool
).
not
.
toHaveProperty
(
'outputs'
);
expect
(
tool
).
not
.
toHaveProperty
(
'secrets'
);
});
it
(
'omits null schemas returned by plugin client'
,
async
()
=>
{
mocks
.
findSystemTool
.
mockResolvedValue
({
pluginId
:
'systemTool-perplexity'
,
status
:
'Normal'
,
currentCost
:
0
,
hasTokenFee
:
false
,
systemKeyCost
:
0
,
customConfig
:
{}
});
mocks
.
findSystemTools
.
mockResolvedValue
([]);
mocks
.
getTool
.
mockResolvedValue
({
source
:
'system'
,
isToolset
:
true
,
name
:
{
en
:
'Perplexity'
},
description
:
{
en
:
'Perplexity intro'
},
pluginId
:
'perplexity'
,
version
:
'0.0.1'
,
icon
:
'perplexity.svg'
,
tags
:
[],
toolDescription
:
'Perplexity tool'
,
inputSchema
:
null
,
outputSchema
:
null
,
secretSchema
:
null
,
children
:
[
{
id
:
'search'
,
name
:
{
en
:
'Search'
},
description
:
{
en
:
'Search intro'
},
toolDescription
:
'Search tool'
,
inputSchema
:
null
,
outputSchema
:
null
}
]
});
const
tool
=
await
SystemToolRepo
.
getInstance
().
getSystemToolDetail
({
pluginId
:
'systemTool-perplexity'
});
expect
(
tool
).
not
.
toHaveProperty
(
'inputSchema'
);
expect
(
tool
).
not
.
toHaveProperty
(
'outputSchema'
);
expect
(
tool
).
not
.
toHaveProperty
(
'secretSchema'
);
expect
(
tool
.
children
?.[
0
]).
not
.
toHaveProperty
(
'inputSchema'
);
expect
(
tool
.
children
?.[
0
]).
not
.
toHaveProperty
(
'outputSchema'
);
});
});
describe
(
'SystemToolRepo.getSystemToolDisplayInfo'
,
()
=>
{
...
...
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