feat: add support for Graph Tools in AIAgent model and related services

This commit is contained in:
mlogclub
2026-04-14 15:10:50 +08:00
parent 8d560bb6bd
commit aa7f94e08f
9 changed files with 213 additions and 19 deletions
@@ -73,16 +73,23 @@ func (c *toolCatalog) parseSkillAllowedToolCodes(skill *models.SkillDefinition)
}
func (c *toolCatalog) parseAgentAllowedToolCodes(aiAgent *models.AIAgent) []string {
if aiAgent == nil || strings.TrimSpace(aiAgent.AllowedMCPTools) == "" {
if aiAgent == nil {
return nil
}
items, err := toolx.ParseAgentMCPToolsJSON(aiAgent.AllowedMCPTools)
if err != nil {
return nil
ret := make([]string, 0)
if raw := strings.TrimSpace(aiAgent.AllowedMCPTools); raw != "" {
items, err := toolx.ParseAgentMCPToolsJSON(raw)
if err == nil {
for _, item := range items {
ret = append(ret, item.ToolCode)
}
}
}
ret := make([]string, 0, len(items))
for _, item := range items {
ret = append(ret, item.ToolCode)
if raw := strings.TrimSpace(aiAgent.AllowedGraphTools); raw != "" {
var graphTools []string
if err := json.Unmarshal([]byte(raw), &graphTools); err == nil {
ret = append(ret, graphTools...)
}
}
return toolx.NormalizeToolCodes(ret)
}
@@ -131,6 +131,7 @@ func buildAIAgentResponse(item *models.AIAgent) response.AIAgentResponse {
Skills: make([]response.AIAgentSkillResponse, 0),
Teams: make([]response.AIAgentTeamResponse, 0),
DirectTools: make([]response.AIAgentMCPToolResponse, 0),
GraphTools: make([]string, 0),
SortNo: item.SortNo,
Remark: item.Remark,
CreatedAt: item.CreatedAt.Format("2006-01-02 15:04:05"),
@@ -175,6 +176,10 @@ func buildAIAgentResponse(item *models.AIAgent) response.AIAgentResponse {
if toolx.IsAutoInjectedToolCode(toolCode) {
continue
}
if toolx.IsAgentDirectGraphToolCode(toolCode) {
ret.GraphTools = appendGraphToolCodeIfMissing(ret.GraphTools, toolCode)
continue
}
serverCode := strings.TrimSpace(tool.ServerCode)
toolName := strings.TrimSpace(tool.ToolName)
if registeredServerCode, registeredToolName, ok := toolx.GetRegisteredToolIdentity(toolCode); ok {
@@ -207,5 +212,30 @@ func buildAIAgentResponse(item *models.AIAgent) response.AIAgentResponse {
}
}
}
if raw := strings.TrimSpace(item.AllowedGraphTools); raw != "" {
var graphTools []string
if err := json.Unmarshal([]byte(raw), &graphTools); err == nil {
for _, toolCode := range graphTools {
toolCode = toolx.NormalizeToolCodeAlias(strings.TrimSpace(toolCode))
if !toolx.IsAgentDirectGraphToolCode(toolCode) {
continue
}
ret.GraphTools = appendGraphToolCodeIfMissing(ret.GraphTools, toolCode)
}
}
}
return ret
}
func appendGraphToolCodeIfMissing(items []string, toolCode string) []string {
toolCode = strings.TrimSpace(toolCode)
if toolCode == "" {
return items
}
for _, item := range items {
if strings.TrimSpace(item) == toolCode {
return items
}
}
return append(items, toolCode)
}
+1
View File
@@ -514,6 +514,7 @@ type AIAgent struct {
KnowledgeIDs string `gorm:"type:varchar(500);not null;default:''"` // KnowledgeIDs 为绑定的知识库ID列表,按顺序表示优先级。
SkillIDs string `gorm:"type:varchar(500);not null;default:''"` // SkillIDs 为绑定的技能ID列表,按顺序表示允许路由的范围。
AllowedMCPTools string `gorm:"type:text"` // AllowedMCPTools 为允许 direct tool 路由的 MCP 工具白名单配置JSON。
AllowedGraphTools string `gorm:"type:text"` // AllowedGraphTools 为允许 Graph Tool 的白名单配置JSON。
SortNo int `gorm:"type:int;not null;default:0;index"` // SortNo 为后台展示排序号。
Remark string `gorm:"type:text"` // Remark 为备注。
AuditFields
+1
View File
@@ -56,6 +56,7 @@ type CreateAIAgentRequest struct {
KnowledgeIDs []int64 `json:"knowledgeIds"`
SkillIDs []int64 `json:"skillIds"`
DirectTools []AIAgentMCPToolRequest `json:"directTools"`
GraphTools []string `json:"graphTools"`
Remark string `json:"remark"`
}
+1
View File
@@ -89,6 +89,7 @@ type AIAgentResponse struct {
SkillIDs []int64 `json:"skillIds"`
Skills []AIAgentSkillResponse `json:"skills"`
DirectTools []AIAgentMCPToolResponse `json:"directTools"`
GraphTools []string `json:"graphTools"`
SortNo int `json:"sortNo"`
Remark string `json:"remark"`
CreatedAt string `json:"createdAt"`
+6
View File
@@ -281,6 +281,12 @@ func IsAgentDirectToolCode(toolCode string) bool {
return ok && spec.DirectAccess
}
func IsAgentDirectGraphToolCode(toolCode string) bool {
toolCode = NormalizeToolCodeAlias(strings.TrimSpace(toolCode))
spec, ok := GetRegisteredToolSpec(toolCode)
return ok && spec.DirectAccess && spec.SourceType == enums.ToolSourceTypeGraph
}
func NormalizeToolCodeAlias(toolCode string) string {
toolCode = strings.TrimSpace(toolCode)
if canonical, ok := toolAliasToCanonical[toolCode]; ok {
+40
View File
@@ -105,6 +105,7 @@ func (s *aIAgentService) UpdateAIAgent(req request.UpdateAIAgentRequest, operato
"knowledge_ids": item.KnowledgeIDs,
"skill_ids": item.SkillIDs,
"allowed_mcp_tools": item.AllowedMCPTools,
"allowed_graph_tools": item.AllowedGraphTools,
"remark": item.Remark,
"update_user_id": operator.UserID,
"update_user_name": operator.Username,
@@ -179,6 +180,10 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
if err != nil {
return nil, err
}
graphTools, err := s.normalizeGraphTools(req.GraphTools)
if err != nil {
return nil, err
}
directToolsJSON := ""
if len(directTools) > 0 {
buf, marshalErr := json.Marshal(directTools)
@@ -187,6 +192,14 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
}
directToolsJSON = string(buf)
}
graphToolsJSON := ""
if len(graphTools) > 0 {
buf, marshalErr := json.Marshal(graphTools)
if marshalErr != nil {
return nil, errorsx.InvalidParam("Graph Tools 配置格式不合法")
}
graphToolsJSON = string(buf)
}
return &models.AIAgent{
Name: name,
Description: strings.TrimSpace(req.Description),
@@ -201,6 +214,7 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
KnowledgeIDs: utils.JoinInt64s(knowledgeIDs),
SkillIDs: utils.JoinInt64s(skillIDs),
AllowedMCPTools: directToolsJSON,
AllowedGraphTools: graphToolsJSON,
Remark: strings.TrimSpace(req.Remark),
}, nil
}
@@ -289,6 +303,9 @@ func (s *aIAgentService) normalizeDirectTools(input []request.AIAgentMCPToolRequ
if toolx.IsAutoInjectedToolCode(strings.TrimSpace(normalized.ToolCode)) {
continue
}
if toolx.ResolveToolSourceType(normalized.ToolCode) != enums.ToolSourceTypeMCP {
return nil, errorsx.InvalidParam("Direct Tools 仅允许配置 MCP 工具")
}
if err := ToolCatalogService.ValidateToolCode(normalized.ToolCode); err != nil {
return nil, err
}
@@ -302,6 +319,29 @@ func (s *aIAgentService) normalizeDirectTools(input []request.AIAgentMCPToolRequ
return ret, nil
}
func (s *aIAgentService) normalizeGraphTools(input []string) ([]string, error) {
if len(input) == 0 {
return nil, nil
}
ret := make([]string, 0, len(input))
seen := make(map[string]struct{})
for _, item := range input {
toolCode := toolx.NormalizeToolCodeAlias(strings.TrimSpace(item))
if toolCode == "" {
continue
}
if !toolx.IsAgentDirectGraphToolCode(toolCode) {
return nil, errorsx.InvalidParam("Graph Tools 仅允许配置 Graph Tool")
}
if _, exists := seen[toolCode]; exists {
continue
}
seen[toolCode] = struct{}{}
ret = append(ret, toolCode)
}
return ret, nil
}
func (s *aIAgentService) UpdateSort(ids []int64) error {
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
for i, id := range ids {