feat: rename AllowedToolCodes to ToolWhitelist across skill-related models and requests for consistency
This commit is contained in:
@@ -113,7 +113,7 @@ func (s *Service) Run(ctx context.Context, req Request) (*Summary, error) {
|
|||||||
if req.SelectedSkill != nil {
|
if req.SelectedSkill != nil {
|
||||||
summary.SelectedSkillCode = strings.TrimSpace(req.SelectedSkill.Code)
|
summary.SelectedSkillCode = strings.TrimSpace(req.SelectedSkill.Code)
|
||||||
summary.SelectedSkillName = strings.TrimSpace(req.SelectedSkill.Name)
|
summary.SelectedSkillName = strings.TrimSpace(req.SelectedSkill.Name)
|
||||||
summary.SkillAllowedToolCodes = parseJSONArrayList(req.SelectedSkill.AllowedToolCodes)
|
summary.SkillAllowedToolCodes = parseJSONArrayList(req.SelectedSkill.ToolWhitelist)
|
||||||
collector.Data.Skill.Code = summary.SelectedSkillCode
|
collector.Data.Skill.Code = summary.SelectedSkillCode
|
||||||
collector.Data.Skill.Name = summary.SelectedSkillName
|
collector.Data.Skill.Name = summary.SelectedSkillName
|
||||||
collector.Data.Skill.AllowedToolCodes = append([]string(nil), summary.SkillAllowedToolCodes...)
|
collector.Data.Skill.AllowedToolCodes = append([]string(nil), summary.SkillAllowedToolCodes...)
|
||||||
@@ -315,7 +315,7 @@ func filterToolDefinitionsBySkill(definitions []adapter.MCPToolDefinition, skill
|
|||||||
if len(definitions) == 0 || skill == nil {
|
if len(definitions) == 0 || skill == nil {
|
||||||
return definitions
|
return definitions
|
||||||
}
|
}
|
||||||
allowed := parseJSONArraySet(skill.AllowedToolCodes)
|
allowed := parseJSONArraySet(skill.ToolWhitelist)
|
||||||
if len(allowed) == 0 {
|
if len(allowed) == 0 {
|
||||||
return definitions
|
return definitions
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ func parseSkillAllowedToolCodes(skill *models.SkillDefinition) []string {
|
|||||||
if skill == nil {
|
if skill == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
raw := strings.TrimSpace(skill.AllowedToolCodes)
|
raw := strings.TrimSpace(skill.ToolWhitelist)
|
||||||
if raw == "" {
|
if raw == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,26 +13,26 @@ func BuildSkillDefinitionResponse(item *models.SkillDefinition) response.SkillDe
|
|||||||
if raw := item.Examples; raw != "" {
|
if raw := item.Examples; raw != "" {
|
||||||
_ = json.Unmarshal([]byte(raw), &examples)
|
_ = json.Unmarshal([]byte(raw), &examples)
|
||||||
}
|
}
|
||||||
allowedToolCodes := make([]string, 0)
|
toolWhitelist := make([]string, 0)
|
||||||
if raw := item.AllowedToolCodes; raw != "" {
|
if raw := item.ToolWhitelist; raw != "" {
|
||||||
_ = json.Unmarshal([]byte(raw), &allowedToolCodes)
|
_ = json.Unmarshal([]byte(raw), &toolWhitelist)
|
||||||
}
|
}
|
||||||
return response.SkillDefinitionResponse{
|
return response.SkillDefinitionResponse{
|
||||||
ID: item.ID,
|
ID: item.ID,
|
||||||
Code: item.Code,
|
Code: item.Code,
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
Description: item.Description,
|
Description: item.Description,
|
||||||
Instruction: item.Instruction,
|
Instruction: item.Instruction,
|
||||||
Examples: examples,
|
Examples: examples,
|
||||||
AllowedToolCodes: allowedToolCodes,
|
ToolWhitelist: toolWhitelist,
|
||||||
Priority: item.Priority,
|
Priority: item.Priority,
|
||||||
Status: int(item.Status),
|
Status: int(item.Status),
|
||||||
StatusName: getSkillStatusName(item.Status),
|
StatusName: getSkillStatusName(item.Status),
|
||||||
Remark: item.Remark,
|
Remark: item.Remark,
|
||||||
CreatedAt: item.CreatedAt,
|
CreatedAt: item.CreatedAt,
|
||||||
UpdatedAt: item.UpdatedAt,
|
UpdatedAt: item.UpdatedAt,
|
||||||
CreateUserName: item.CreateUserName,
|
CreateUserName: item.CreateUserName,
|
||||||
UpdateUserName: item.UpdateUserName,
|
UpdateUserName: item.UpdateUserName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -904,16 +904,16 @@ type KnowledgeFeedback struct {
|
|||||||
|
|
||||||
// SkillDefinition 表示可由后台配置并参与运行时路由的 Skill 定义。
|
// SkillDefinition 表示可由后台配置并参与运行时路由的 Skill 定义。
|
||||||
type SkillDefinition struct {
|
type SkillDefinition struct {
|
||||||
ID int64 `gorm:"primaryKey;autoIncrement"` // ID 为 Skill 主键。
|
ID int64 `gorm:"primaryKey;autoIncrement"` // ID 为 Skill 主键。
|
||||||
Code string `gorm:"type:varchar(100);not null;default:'';uniqueIndex"` // Code 为 Skill 的稳定唯一编码,供程序内部引用和路由判断使用,例如 refund_skill。
|
Code string `gorm:"type:varchar(100);not null;default:'';uniqueIndex"` // Code 为 Skill 的稳定唯一编码,供程序内部引用和路由判断使用,例如 refund_skill。
|
||||||
Name string `gorm:"type:varchar(100);not null;default:'';index"` // Name 为 Skill 的展示名称,用于后台列表、配置页和人工选择场景。
|
Name string `gorm:"type:varchar(100);not null;default:'';index"` // Name 为 Skill 的展示名称,用于后台列表、配置页和人工选择场景。
|
||||||
Description string `gorm:"type:varchar(255);not null;default:''"` // Description 为 Skill 的简要说明,用于描述该 Skill 的适用场景和职责边界。
|
Description string `gorm:"type:varchar(255);not null;default:''"` // Description 为 Skill 的简要说明,用于描述该 Skill 的适用场景和职责边界。
|
||||||
Instruction string `gorm:"type:longtext"` // Instruction 为 Skill 的主体说明文档存储字段,使用 Markdown 编写,供 Agent 理解任务目标、步骤和工具使用要求。
|
Instruction string `gorm:"type:longtext"` // Instruction 为 Skill 的主体说明文档存储字段,使用 Markdown 编写,供 Agent 理解任务目标、步骤和工具使用要求。
|
||||||
Examples string `gorm:"type:text"` // Examples 为示例问法 JSON 数组字符串。
|
Examples string `gorm:"type:text"` // Examples 为示例问法 JSON 数组字符串。
|
||||||
AllowedToolCodes string `gorm:"type:text"` // AllowedToolCodes 为允许使用的工具编码 JSON 数组字符串。
|
ToolWhitelist string `gorm:"type:text"` // ToolWhitelist 为允许使用的工具编码 JSON 数组字符串。
|
||||||
Priority int `gorm:"type:int;not null;default:0;index"` // Priority 为 Skill 命中冲突时的优先级,数值越大优先级越高。
|
Priority int `gorm:"type:int;not null;default:0;index"` // Priority 为 Skill 命中冲突时的优先级,数值越大优先级越高。
|
||||||
Status enums.Status `gorm:"type:int;not null;default:0;index"` // Status 为 Skill 当前状态,使用全局通用状态:0启用 1禁用 2删除。
|
Status enums.Status `gorm:"type:int;not null;default:0;index"` // Status 为 Skill 当前状态,使用全局通用状态:0启用 1禁用 2删除。
|
||||||
Remark string `gorm:"type:text"` // Remark 为后台备注,用于记录配置说明、维护信息或内部协作信息。
|
Remark string `gorm:"type:text"` // Remark 为后台备注,用于记录配置说明、维护信息或内部协作信息。
|
||||||
AuditFields
|
AuditFields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ type SkillDefinitionListRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreateSkillDefinitionRequest struct {
|
type CreateSkillDefinitionRequest struct {
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Instruction string `json:"instruction"`
|
Instruction string `json:"instruction"`
|
||||||
Examples []string `json:"examples"`
|
Examples []string `json:"examples"`
|
||||||
AllowedToolCodes []string `json:"allowedToolCodes"`
|
ToolWhitelist []string `json:"toolWhitelist"`
|
||||||
Priority int `json:"priority"`
|
Priority int `json:"priority"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateSkillDefinitionRequest struct {
|
type UpdateSkillDefinitionRequest struct {
|
||||||
|
|||||||
@@ -3,21 +3,21 @@ package response
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type SkillDefinitionResponse struct {
|
type SkillDefinitionResponse struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Instruction string `json:"instruction"`
|
Instruction string `json:"instruction"`
|
||||||
Examples []string `json:"examples"`
|
Examples []string `json:"examples"`
|
||||||
AllowedToolCodes []string `json:"allowedToolCodes"`
|
ToolWhitelist []string `json:"toolWhitelist"`
|
||||||
Priority int `json:"priority"`
|
Priority int `json:"priority"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
StatusName string `json:"statusName"`
|
StatusName string `json:"statusName"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
CreateUserName string `json:"createUserName"`
|
CreateUserName string `json:"createUserName"`
|
||||||
UpdateUserName string `json:"updateUserName"`
|
UpdateUserName string `json:"updateUserName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkillDebugRunResponse struct {
|
type SkillDebugRunResponse struct {
|
||||||
|
|||||||
@@ -109,16 +109,16 @@ func (s *skillDefinitionService) CreateSkillDefinition(req request.CreateSkillDe
|
|||||||
return nil, errorsx.InvalidParam("Skill 编码已存在")
|
return nil, errorsx.InvalidParam("Skill 编码已存在")
|
||||||
}
|
}
|
||||||
item := &models.SkillDefinition{
|
item := &models.SkillDefinition{
|
||||||
Code: normalized.Code,
|
Code: normalized.Code,
|
||||||
Name: normalized.Name,
|
Name: normalized.Name,
|
||||||
Description: normalized.Description,
|
Description: normalized.Description,
|
||||||
Instruction: normalized.Instruction,
|
Instruction: normalized.Instruction,
|
||||||
Examples: mustMarshalSkillStringArray(normalized.Examples),
|
Examples: mustMarshalSkillStringArray(normalized.Examples),
|
||||||
AllowedToolCodes: mustMarshalSkillStringArray(normalized.AllowedToolCodes),
|
ToolWhitelist: mustMarshalSkillStringArray(normalized.ToolWhitelist),
|
||||||
Priority: normalized.Priority,
|
Priority: normalized.Priority,
|
||||||
Status: enums.StatusOk,
|
Status: enums.StatusOk,
|
||||||
Remark: normalized.Remark,
|
Remark: normalized.Remark,
|
||||||
AuditFields: utils.BuildAuditFields(operator),
|
AuditFields: utils.BuildAuditFields(operator),
|
||||||
}
|
}
|
||||||
if item.Priority <= 0 {
|
if item.Priority <= 0 {
|
||||||
item.Priority = s.NextPriority()
|
item.Priority = s.NextPriority()
|
||||||
@@ -151,9 +151,9 @@ func (s *skillDefinitionService) UpdateSkillDefinition(req request.UpdateSkillDe
|
|||||||
"code": normalized.Code,
|
"code": normalized.Code,
|
||||||
"name": normalized.Name,
|
"name": normalized.Name,
|
||||||
"description": normalized.Description,
|
"description": normalized.Description,
|
||||||
"content": normalized.Instruction,
|
"instruction": normalized.Instruction,
|
||||||
"examples": mustMarshalSkillStringArray(normalized.Examples),
|
"examples": mustMarshalSkillStringArray(normalized.Examples),
|
||||||
"allowed_tool_codes": mustMarshalSkillStringArray(normalized.AllowedToolCodes),
|
"allowed_tool_codes": mustMarshalSkillStringArray(normalized.ToolWhitelist),
|
||||||
"priority": resolveSkillPriorityForService(normalized.Priority, current.Priority),
|
"priority": resolveSkillPriorityForService(normalized.Priority, current.Priority),
|
||||||
"remark": normalized.Remark,
|
"remark": normalized.Remark,
|
||||||
"update_user_id": operator.UserID,
|
"update_user_id": operator.UserID,
|
||||||
@@ -184,17 +184,17 @@ func (s *skillDefinitionService) normalizeSkillDefinitionRequest(req request.Cre
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
allowedToolCodes, err := normalizeSkillStringArray(req.AllowedToolCodes)
|
toolWhitelist, err := normalizeSkillStringArray(req.ToolWhitelist)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, toolCode := range allowedToolCodes {
|
for _, toolCode := range toolWhitelist {
|
||||||
if err := ToolCatalogService.ValidateMCPToolCode(toolCode); err != nil {
|
if err := ToolCatalogService.ValidateMCPToolCode(toolCode); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
normalized.Examples = examples
|
normalized.Examples = examples
|
||||||
normalized.AllowedToolCodes = allowedToolCodes
|
normalized.ToolWhitelist = toolWhitelist
|
||||||
return normalized, nil
|
return normalized, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ function buildForm(item: SkillDefinition | null): EditForm {
|
|||||||
|
|
||||||
function buildPayload(
|
function buildPayload(
|
||||||
form: EditForm,
|
form: EditForm,
|
||||||
allowedToolCodes: string[],
|
toolWhitelist: string[],
|
||||||
): CreateSkillDefinitionPayload {
|
): CreateSkillDefinitionPayload {
|
||||||
return {
|
return {
|
||||||
code: form.code.trim(),
|
code: form.code.trim(),
|
||||||
@@ -90,7 +90,7 @@ function buildPayload(
|
|||||||
.split("\n")
|
.split("\n")
|
||||||
.map((item) => item.trim())
|
.map((item) => item.trim())
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
allowedToolCodes,
|
toolWhitelist,
|
||||||
remark: form.remark.trim(),
|
remark: form.remark.trim(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@ function SkillEditDialogBody({
|
|||||||
const formId = "skill-definition-edit-form";
|
const formId = "skill-definition-edit-form";
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [toolCatalog, setToolCatalog] = useState<MCPToolCatalogItem[]>([]);
|
const [toolCatalog, setToolCatalog] = useState<MCPToolCatalogItem[]>([]);
|
||||||
const [selectedAllowedToolCodes, setSelectedAllowedToolCodes] = useState<
|
const [selectedToolWhitelist, setSelectedToolWhitelist] = useState<
|
||||||
string[]
|
string[]
|
||||||
>([]);
|
>([]);
|
||||||
const [toolCodeToAdd, setToolCodeToAdd] = useState("");
|
const [toolCodeToAdd, setToolCodeToAdd] = useState("");
|
||||||
@@ -154,7 +154,7 @@ function SkillEditDialogBody({
|
|||||||
async function loadDetail() {
|
async function loadDetail() {
|
||||||
if (!itemId) {
|
if (!itemId) {
|
||||||
reset(emptyForm);
|
reset(emptyForm);
|
||||||
setSelectedAllowedToolCodes([]);
|
setSelectedToolWhitelist([]);
|
||||||
setToolCodeToAdd("");
|
setToolCodeToAdd("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ function SkillEditDialogBody({
|
|||||||
try {
|
try {
|
||||||
const data = await fetchSkillDefinition(itemId);
|
const data = await fetchSkillDefinition(itemId);
|
||||||
reset(buildForm(data));
|
reset(buildForm(data));
|
||||||
setSelectedAllowedToolCodes(data.allowedToolCodes ?? []);
|
setSelectedToolWhitelist(data.toolWhitelist ?? []);
|
||||||
setToolCodeToAdd("");
|
setToolCodeToAdd("");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to load skill definition:", error);
|
console.error("Failed to load skill definition:", error);
|
||||||
@@ -189,7 +189,7 @@ function SkillEditDialogBody({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
async function onFormSubmit(values: EditForm) {
|
async function onFormSubmit(values: EditForm) {
|
||||||
await onSubmit(buildPayload(values, selectedAllowedToolCodes));
|
await onSubmit(buildPayload(values, selectedToolWhitelist));
|
||||||
}
|
}
|
||||||
|
|
||||||
const toolOptions = useMemo(
|
const toolOptions = useMemo(
|
||||||
@@ -204,31 +204,31 @@ function SkillEditDialogBody({
|
|||||||
const addableToolOptions = useMemo(
|
const addableToolOptions = useMemo(
|
||||||
() =>
|
() =>
|
||||||
toolOptions.filter(
|
toolOptions.filter(
|
||||||
(option) => !selectedAllowedToolCodes.includes(option.value),
|
(option) => !selectedToolWhitelist.includes(option.value),
|
||||||
),
|
),
|
||||||
[selectedAllowedToolCodes, toolOptions],
|
[selectedToolWhitelist, toolOptions],
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedToolOptions = useMemo(
|
const selectedToolOptions = useMemo(
|
||||||
() =>
|
() =>
|
||||||
selectedAllowedToolCodes
|
selectedToolWhitelist
|
||||||
.map((toolCode) => toolOptions.find((option) => option.value === toolCode))
|
.map((toolCode) => toolOptions.find((option) => option.value === toolCode))
|
||||||
.filter(
|
.filter(
|
||||||
(option): option is { value: string; label: string } => !!option,
|
(option): option is { value: string; label: string } => !!option,
|
||||||
),
|
),
|
||||||
[selectedAllowedToolCodes, toolOptions],
|
[selectedToolWhitelist, toolOptions],
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleAddAllowedTool(toolCode: string) {
|
function handleAddToolWhitelist(toolCode: string) {
|
||||||
if (!toolCode || selectedAllowedToolCodes.includes(toolCode)) {
|
if (!toolCode || selectedToolWhitelist.includes(toolCode)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSelectedAllowedToolCodes((prev) => [...prev, toolCode]);
|
setSelectedToolWhitelist((prev) => [...prev, toolCode]);
|
||||||
setToolCodeToAdd("");
|
setToolCodeToAdd("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRemoveAllowedTool(toolCode: string) {
|
function handleRemoveToolWhitelist(toolCode: string) {
|
||||||
setSelectedAllowedToolCodes((prev) =>
|
setSelectedToolWhitelist((prev) =>
|
||||||
prev.filter((item) => item !== toolCode),
|
prev.filter((item) => item !== toolCode),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -336,24 +336,24 @@ function SkillEditDialogBody({
|
|||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<FieldLabel>Allowed Tools</FieldLabel>
|
<FieldLabel>工具白名单</FieldLabel>
|
||||||
<FieldContent className="space-y-3">
|
<FieldContent className="space-y-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<OptionCombobox
|
<OptionCombobox
|
||||||
value={toolCodeToAdd}
|
value={toolCodeToAdd}
|
||||||
options={addableToolOptions}
|
options={addableToolOptions}
|
||||||
placeholder="选择允许该 Skill 使用的工具"
|
placeholder="选择该 Skill 允许使用的工具"
|
||||||
searchPlaceholder="搜索 toolCode 或工具名"
|
searchPlaceholder="搜索 toolCode 或工具名"
|
||||||
emptyText="没有可添加的工具"
|
emptyText="没有可添加的工具"
|
||||||
onChange={handleAddAllowedTool}
|
onChange={handleAddToolWhitelist}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
disabled={!toolCodeToAdd}
|
disabled={!toolCodeToAdd}
|
||||||
onClick={() => handleAddAllowedTool(toolCodeToAdd)}
|
onClick={() => handleAddToolWhitelist(toolCodeToAdd)}
|
||||||
>
|
>
|
||||||
添加
|
添加
|
||||||
</Button>
|
</Button>
|
||||||
@@ -370,7 +370,7 @@ function SkillEditDialogBody({
|
|||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => handleRemoveAllowedTool(option.value)}
|
onClick={() => handleRemoveToolWhitelist(option.value)}
|
||||||
className="justify-start"
|
className="justify-start"
|
||||||
>
|
>
|
||||||
{option.label}
|
{option.label}
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ export type SkillDefinition = {
|
|||||||
description: string
|
description: string
|
||||||
instruction: string
|
instruction: string
|
||||||
examples: string[]
|
examples: string[]
|
||||||
allowedToolCodes: string[]
|
toolWhitelist: string[]
|
||||||
priority: number
|
priority: number
|
||||||
status: number
|
status: number
|
||||||
statusName: string
|
statusName: string
|
||||||
@@ -292,7 +292,7 @@ export type CreateSkillDefinitionPayload = {
|
|||||||
description: string
|
description: string
|
||||||
instruction: string
|
instruction: string
|
||||||
examples: string[]
|
examples: string[]
|
||||||
allowedToolCodes: string[]
|
toolWhitelist: string[]
|
||||||
priority?: number
|
priority?: number
|
||||||
remark: string
|
remark: string
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user