refactor: rename direct tools to MCP tools across the codebase for consistency
This commit is contained in:
@@ -61,7 +61,7 @@ func TestRegistryIncludesAllTicketDraftToolInputs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryTreatsAdministratorSelectedMCPToolsAsDirectTools(t *testing.T) {
|
||||
func TestRegistryTreatsAdministratorSelectedMCPToolsAsAllowedTools(t *testing.T) {
|
||||
definition, err := DefaultRegistry.Resolve("knowledge/search")
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve returned error: %v", err)
|
||||
|
||||
@@ -270,7 +270,7 @@ func buildAIAgentResponseWithLocale(item *models.AIAgent, locale string) respons
|
||||
SkillIDs: utils.SplitInt64s(item.SkillIDs),
|
||||
Skills: make([]response.AIAgentSkillResponse, 0),
|
||||
Teams: make([]response.AIAgentTeamResponse, 0),
|
||||
DirectTools: make([]response.AIAgentMCPToolResponse, 0),
|
||||
MCPTools: make([]response.AIAgentMCPToolResponse, 0),
|
||||
WorkflowBindings: make([]response.AIAgentWorkflowBindingResponse, 0),
|
||||
WorkflowVersionID: item.WorkflowVersionID,
|
||||
PublishedRevisionID: item.PublishedRevisionID,
|
||||
@@ -303,18 +303,15 @@ func buildAIAgentResponseWithLocale(item *models.AIAgent, locale string) respons
|
||||
}
|
||||
}
|
||||
if raw := strings.TrimSpace(item.AllowedMCPTools); raw != "" {
|
||||
var directTools []request.AIAgentMCPToolRequest
|
||||
if err := json.Unmarshal([]byte(raw), &directTools); err == nil {
|
||||
for _, tool := range directTools {
|
||||
var mcpTools []request.AIAgentMCPToolRequest
|
||||
if err := json.Unmarshal([]byte(raw), &mcpTools); err == nil {
|
||||
for _, tool := range mcpTools {
|
||||
toolCode := strings.TrimSpace(tool.ToolCode)
|
||||
if toolCode == "" {
|
||||
toolCode = toolx.BuildMCPToolCode(tool.ServerCode, tool.ToolName)
|
||||
}
|
||||
toolCode = toolx.NormalizeToolCodeAlias(toolCode)
|
||||
if toolx.IsAutoInjectedToolCode(toolCode) {
|
||||
continue
|
||||
}
|
||||
if toolx.IsAgentDirectGraphToolCode(toolCode) {
|
||||
if toolx.ResolveToolSourceType(toolCode) != enums.ToolSourceTypeMCP {
|
||||
continue
|
||||
}
|
||||
serverCode := strings.TrimSpace(tool.ServerCode)
|
||||
@@ -338,7 +335,7 @@ func buildAIAgentResponseWithLocale(item *models.AIAgent, locale string) respons
|
||||
description = registeredDescription
|
||||
}
|
||||
}
|
||||
ret.DirectTools = append(ret.DirectTools, response.AIAgentMCPToolResponse{
|
||||
ret.MCPTools = append(ret.MCPTools, response.AIAgentMCPToolResponse{
|
||||
ToolCode: toolCode,
|
||||
ServerCode: serverCode,
|
||||
ToolName: toolName,
|
||||
|
||||
@@ -552,7 +552,7 @@ type AIAgent struct {
|
||||
FallbackMessage string `gorm:"type:text"` // FallbackMessage 为知识不足回复文案。
|
||||
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。
|
||||
AllowedMCPTools string `gorm:"type:text"` // AllowedMCPTools 为 Agent 允许调用的 MCP 工具白名单配置 JSON。
|
||||
WorkflowVersionID int64 `gorm:"type:bigint;not null;default:0;index"` // WorkflowVersionID is retained as the single-workflow runtime pointer.
|
||||
PublishedRevisionID int64 `gorm:"type:bigint;not null;default:0;index"` // PublishedRevisionID 为当前已发布 Agent 配置快照ID。
|
||||
SortNo int `gorm:"type:int;not null;default:0;index"` // SortNo 为后台展示排序号。
|
||||
|
||||
@@ -70,7 +70,7 @@ type CreateAIAgentRequest struct {
|
||||
FallbackMessage string `json:"fallbackMessage"`
|
||||
KnowledgeBaseIDs []int64 `json:"knowledgeBaseIds"`
|
||||
SkillIDs []int64 `json:"skillIds"`
|
||||
DirectTools []AIAgentMCPToolRequest `json:"directTools"`
|
||||
MCPTools []AIAgentMCPToolRequest `json:"mcpTools"`
|
||||
WorkflowBindings []AIAgentWorkflowBindingRequest `json:"workflowBindings"`
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ type AIAgentResponse struct {
|
||||
KnowledgeBaseIDs []int64 `json:"knowledgeBaseIds"`
|
||||
SkillIDs []int64 `json:"skillIds"`
|
||||
Skills []AIAgentSkillResponse `json:"skills"`
|
||||
DirectTools []AIAgentMCPToolResponse `json:"directTools"`
|
||||
MCPTools []AIAgentMCPToolResponse `json:"mcpTools"`
|
||||
WorkflowBindings []AIAgentWorkflowBindingResponse `json:"workflowBindings"`
|
||||
WorkflowVersionID int64 `json:"workflowVersionId"`
|
||||
PublishedRevisionID int64 `json:"publishedRevisionId"`
|
||||
|
||||
@@ -12,12 +12,12 @@ error.e0011: "The AI configuration is not enabled."
|
||||
error.e0012: "AI configuration not found."
|
||||
error.e0014: "Checkpoint not found."
|
||||
error.e0015: "The checkpoint does not belong to this AI Agent."
|
||||
error.e0016: "Direct Tool toolCode does not match serverCode."
|
||||
error.e0017: "Direct Tool toolCode does not match toolName."
|
||||
error.e0018: "Invalid Direct Tool toolCode format."
|
||||
error.e0019: "Direct Tool toolCode, serverCode, and toolName are required."
|
||||
error.e0020: "Direct Tools can only contain MCP tools."
|
||||
error.e0021: "Invalid Direct Tools configuration format."
|
||||
error.e0016: "MCP Tool toolCode does not match serverCode."
|
||||
error.e0017: "MCP Tool toolCode does not match toolName."
|
||||
error.e0018: "Invalid MCP Tool toolCode format."
|
||||
error.e0019: "MCP Tool toolCode, serverCode, and toolName are required."
|
||||
error.e0020: "Only MCP Tools can be configured."
|
||||
error.e0021: "Invalid MCP Tool configuration."
|
||||
error.e0022: "The Excel file is empty."
|
||||
error.e0023: "Failed to parse the Excel file."
|
||||
error.e0024: "Failed to read the Excel file."
|
||||
|
||||
@@ -12,12 +12,12 @@ error.e0011: "AI 配置未启用"
|
||||
error.e0012: "AI配置不存在"
|
||||
error.e0014: "CheckPoint 不存在"
|
||||
error.e0015: "CheckPoint 与 AI Agent 不匹配"
|
||||
error.e0016: "Direct Tool 的 toolCode 与 serverCode 不一致"
|
||||
error.e0017: "Direct Tool 的 toolCode 与 toolName 不一致"
|
||||
error.e0018: "Direct Tool 的 toolCode 格式不合法"
|
||||
error.e0019: "Direct Tool 的 toolCode、serverCode 和 toolName 不能为空"
|
||||
error.e0020: "Direct Tools 仅允许配置 MCP 工具"
|
||||
error.e0021: "Direct Tools 配置格式不合法"
|
||||
error.e0016: "MCP Tool 的 toolCode 与 serverCode 不一致"
|
||||
error.e0017: "MCP Tool 的 toolCode 与 toolName 不一致"
|
||||
error.e0018: "MCP Tool 的 toolCode 格式不合法"
|
||||
error.e0019: "MCP Tool 的 toolCode、serverCode 和 toolName 不能为空"
|
||||
error.e0020: "仅允许配置 MCP Tool"
|
||||
error.e0021: "MCP Tool 配置格式不合法"
|
||||
error.e0022: "Excel文件为空"
|
||||
error.e0023: "Excel文件解析失败"
|
||||
error.e0024: "Excel文件读取失败"
|
||||
|
||||
@@ -238,17 +238,17 @@ func (s *aIAgentService) validatePublishableAgent(db *gorm.DB, agent *models.AIA
|
||||
if strings.TrimSpace(agent.AllowedMCPTools) == "" {
|
||||
return nil
|
||||
}
|
||||
var directTools []request.AIAgentMCPToolRequest
|
||||
if err := json.Unmarshal([]byte(agent.AllowedMCPTools), &directTools); err != nil {
|
||||
return errorsx.InvalidParam("ai agent direct tools are invalid")
|
||||
var mcpTools []request.AIAgentMCPToolRequest
|
||||
if err := json.Unmarshal([]byte(agent.AllowedMCPTools), &mcpTools); err != nil {
|
||||
return errorsx.InvalidParam("ai agent MCP tools are invalid")
|
||||
}
|
||||
for _, item := range directTools {
|
||||
for _, item := range mcpTools {
|
||||
definition, err := aitooling.DefaultRegistry.Resolve(item.ToolCode)
|
||||
if err != nil || definition.InputSchema == nil {
|
||||
return errorsx.InvalidParam("ai agent direct tool definition is unavailable")
|
||||
return errorsx.InvalidParam("ai agent MCP tool definition is unavailable")
|
||||
}
|
||||
if definition.RequireConfirmation {
|
||||
return errorsx.InvalidParam("ai agent direct tool requires confirmation and cannot be executed directly")
|
||||
return errorsx.InvalidParam("ai agent MCP tool requires confirmation and cannot be executed directly")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -392,17 +392,17 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
directTools, err := s.normalizeDirectTools(req.DirectTools)
|
||||
mcpTools, err := s.normalizeMCPTools(req.MCPTools)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
directToolsJSON := ""
|
||||
if len(directTools) > 0 {
|
||||
buf, marshalErr := json.Marshal(directTools)
|
||||
mcpToolsJSON := ""
|
||||
if len(mcpTools) > 0 {
|
||||
buf, marshalErr := json.Marshal(mcpTools)
|
||||
if marshalErr != nil {
|
||||
return nil, errorsx.InvalidParamI18n("error.e0021")
|
||||
}
|
||||
directToolsJSON = string(buf)
|
||||
mcpToolsJSON = string(buf)
|
||||
}
|
||||
return &models.AIAgent{
|
||||
Name: name,
|
||||
@@ -424,7 +424,7 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
|
||||
FallbackMessage: strings.TrimSpace(req.FallbackMessage),
|
||||
KnowledgeIDs: utils.JoinInt64s(knowledgeBaseIDs),
|
||||
SkillIDs: utils.JoinInt64s(skillIDs),
|
||||
AllowedMCPTools: directToolsJSON,
|
||||
AllowedMCPTools: mcpToolsJSON,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -541,7 +541,7 @@ func (s *aIAgentService) normalizeSkillIDs(input []int64) ([]int64, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *aIAgentService) normalizeDirectTools(input []request.AIAgentMCPToolRequest) ([]request.AIAgentMCPToolRequest, error) {
|
||||
func (s *aIAgentService) normalizeMCPTools(input []request.AIAgentMCPToolRequest) ([]request.AIAgentMCPToolRequest, error) {
|
||||
if len(input) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -552,20 +552,11 @@ func (s *aIAgentService) normalizeDirectTools(input []request.AIAgentMCPToolRequ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if toolx.IsAutoInjectedToolCode(strings.TrimSpace(normalized.ToolCode)) {
|
||||
continue
|
||||
if toolx.ResolveToolSourceType(normalized.ToolCode) != enums.ToolSourceTypeMCP {
|
||||
return nil, errorsx.InvalidParamI18n("error.e0020")
|
||||
}
|
||||
if spec, registered := toolx.GetRegisteredToolSpec(normalized.ToolCode); registered {
|
||||
if !spec.DirectAccess || spec.AutoInjected || (spec.Code != toolx.BuiltinConversationContext.Code && spec.Code != toolx.BuiltinKnowledgeRetrieve.Code && spec.Code != toolx.GraphTriageServiceRequest.Code && spec.Code != toolx.GraphAnalyzeConversation.Code && spec.Code != toolx.GraphPrepareTicketDraft.Code) {
|
||||
return nil, errorsx.InvalidParamI18n("error.e0020")
|
||||
}
|
||||
} else {
|
||||
if toolx.ResolveToolSourceType(normalized.ToolCode) != enums.ToolSourceTypeMCP {
|
||||
return nil, errorsx.InvalidParamI18n("error.e0020")
|
||||
}
|
||||
if err := ToolCatalogService.ValidateToolCode(normalized.ToolCode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ToolCatalogService.ValidateToolCode(normalized.ToolCode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := strings.TrimSpace(normalized.ToolCode)
|
||||
if _, exists := seen[key]; exists {
|
||||
|
||||
@@ -203,32 +203,18 @@ func TestAIAgentServiceNormalizesToolPolicy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAIAgentServiceAllowsRegisteredReadDirectTool(t *testing.T) {
|
||||
tools, err := AIAgentService.normalizeDirectTools([]request.AIAgentMCPToolRequest{{ToolCode: toolx.BuiltinConversationContext.Code}})
|
||||
if err != nil {
|
||||
t.Fatalf("normalizeDirectTools: %v", err)
|
||||
}
|
||||
if len(tools) != 1 || tools[0].ToolCode != toolx.BuiltinConversationContext.Code {
|
||||
t.Fatalf("unexpected normalized direct tools: %#v", tools)
|
||||
}
|
||||
tools, err = AIAgentService.normalizeDirectTools([]request.AIAgentMCPToolRequest{{ToolCode: toolx.BuiltinKnowledgeRetrieve.Code}})
|
||||
if err != nil || len(tools) != 1 || tools[0].ToolCode != toolx.BuiltinKnowledgeRetrieve.Code {
|
||||
t.Fatalf("expected registered knowledge retrieve tool to be allowed, tools=%#v err=%v", tools, err)
|
||||
}
|
||||
tools, err = AIAgentService.normalizeDirectTools([]request.AIAgentMCPToolRequest{{ToolCode: toolx.GraphPrepareTicketDraft.Code}})
|
||||
if err != nil || len(tools) != 1 || tools[0].ToolCode != toolx.GraphPrepareTicketDraft.Code {
|
||||
t.Fatalf("expected registered ticket draft tool to be allowed, tools=%#v err=%v", tools, err)
|
||||
}
|
||||
tools, err = AIAgentService.normalizeDirectTools([]request.AIAgentMCPToolRequest{{ToolCode: toolx.GraphAnalyzeConversation.Code}})
|
||||
if err != nil || len(tools) != 1 || tools[0].ToolCode != toolx.GraphAnalyzeConversation.Code {
|
||||
t.Fatalf("expected registered conversation analysis tool to be allowed, tools=%#v err=%v", tools, err)
|
||||
}
|
||||
tools, err = AIAgentService.normalizeDirectTools([]request.AIAgentMCPToolRequest{{ToolCode: toolx.GraphTriageServiceRequest.Code}})
|
||||
if err != nil || len(tools) != 1 || tools[0].ToolCode != toolx.GraphTriageServiceRequest.Code {
|
||||
t.Fatalf("expected registered service triage tool to be allowed, tools=%#v err=%v", tools, err)
|
||||
}
|
||||
if _, err := AIAgentService.normalizeDirectTools([]request.AIAgentMCPToolRequest{{ToolCode: toolx.GraphHandoffConversation.Code}}); err == nil {
|
||||
t.Fatal("expected unsupported graph direct tool to be rejected")
|
||||
func TestAIAgentServiceRejectsNonMCPToolSelection(t *testing.T) {
|
||||
for _, toolCode := range []string{
|
||||
toolx.BuiltinConversationContext.Code,
|
||||
toolx.BuiltinKnowledgeRetrieve.Code,
|
||||
toolx.GraphPrepareTicketDraft.Code,
|
||||
toolx.GraphAnalyzeConversation.Code,
|
||||
toolx.GraphTriageServiceRequest.Code,
|
||||
toolx.GraphHandoffConversation.Code,
|
||||
} {
|
||||
if _, err := AIAgentService.normalizeMCPTools([]request.AIAgentMCPToolRequest{{ToolCode: toolCode}}); err == nil {
|
||||
t.Fatalf("expected non-MCP tool %q to be rejected", toolCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +336,7 @@ func TestAIAgentServiceAllowsPublishWithAdministratorSelectedMCPTool(t *testing.
|
||||
t.Fatalf("CreateAIAgent() error = %v", err)
|
||||
}
|
||||
if err := sqls.DB().Model(&models.AIAgent{}).Where("id = ?", agent.ID).Update("allowed_mcp_tools", `[{"toolCode":"mcp/demo/write_order"}]`).Error; err != nil {
|
||||
t.Fatalf("set direct tool: %v", err)
|
||||
t.Fatalf("set MCP tool: %v", err)
|
||||
}
|
||||
if _, err := AIAgentService.PublishAIAgent(agent.ID, operator); err != nil {
|
||||
t.Fatalf("expected administrator-selected MCP tool to be publishable, got %v", err)
|
||||
|
||||
Reference in New Issue
Block a user