From d4ff0980c4b0f7b95513241f41e6b2e2c909a2b2 Mon Sep 17 00:00:00 2001 From: mlogclub Date: Fri, 26 Jun 2026 18:56:09 +0800 Subject: [PATCH] refactor: remove graph tools references and related logic from AIAgent and workflows --- .../application/runtime/workflow_runtime.go | 14 ----- .../runtime/workflow_summary_test.go | 34 +++++++++++ internal/ai/workflow/compiler/compiler.go | 60 ------------------- .../ai/workflow/compiler/compiler_test.go | 39 ------------ .../handlers/dashboard/ai_agent_handler.go | 27 --------- internal/models/models.go | 1 - internal/pkg/dto/request/ai_request.go | 1 - internal/pkg/dto/response/ai_response.go | 1 - internal/services/ai_agent_service.go | 37 ------------ .../config-workbench-copy.test.mjs | 12 ++++ .../_components/config-workbench.tsx | 1 - web/lib/api/admin.ts | 2 - web/messages/en-US.json | 9 +-- web/messages/zh-CN.json | 9 +-- 14 files changed, 48 insertions(+), 199 deletions(-) delete mode 100644 internal/ai/workflow/compiler/compiler.go delete mode 100644 internal/ai/workflow/compiler/compiler_test.go diff --git a/internal/ai/application/runtime/workflow_runtime.go b/internal/ai/application/runtime/workflow_runtime.go index 470923b..4d3510d 100644 --- a/internal/ai/application/runtime/workflow_runtime.go +++ b/internal/ai/application/runtime/workflow_runtime.go @@ -2,9 +2,7 @@ package runtime import ( "encoding/json" - "strings" - "agent-desk/internal/ai/workflow/compiler" "agent-desk/internal/ai/workflow/dsl" "agent-desk/internal/models" "agent-desk/internal/pkg/enums" @@ -16,7 +14,6 @@ import ( type resolvedWorkflow struct { Definition dsl.Definition - Compiled compiler.Result WorkflowID int64 VersionID int64 } @@ -35,7 +32,6 @@ func resolveAgentWorkflow(aiAgent models.AIAgent) (resolvedWorkflow, error) { } return resolvedWorkflow{ Definition: def, - Compiled: compiler.Compile(def), WorkflowID: version.WorkflowID, VersionID: version.ID, }, nil @@ -46,15 +42,5 @@ func prepareWorkflowAgent(aiAgent models.AIAgent) (models.AIAgent, resolvedWorkf if err != nil { return aiAgent, resolvedWorkflow{}, err } - if strings.TrimSpace(workflow.Compiled.Appendix) == "" { - return aiAgent, workflow, nil - } - prompt := strings.TrimSpace(aiAgent.SystemPrompt) - appendix := strings.TrimSpace(workflow.Compiled.Appendix) - if prompt == "" { - aiAgent.SystemPrompt = appendix - return aiAgent, workflow, nil - } - aiAgent.SystemPrompt = prompt + "\n\n" + appendix return aiAgent, workflow, nil } diff --git a/internal/ai/application/runtime/workflow_summary_test.go b/internal/ai/application/runtime/workflow_summary_test.go index 724c203..724504b 100644 --- a/internal/ai/application/runtime/workflow_summary_test.go +++ b/internal/ai/application/runtime/workflow_summary_test.go @@ -46,6 +46,40 @@ func TestToWorkflowSummaryPreservesInterruptCheckpoint(t *testing.T) { } } +func TestPrepareWorkflowAgentDoesNotInjectWorkflowAppendix(t *testing.T) { + db := setupWorkflowResumeTestDB(t) + definitionJSON := mustMarshalDefinition(t, dsl.Definition{ + SchemaVersion: 1, + EntryNodeID: "start", + Nodes: []dsl.Node{ + {ID: "start", Type: workflowregistry.NodeTypeStart, Name: "Start"}, + {ID: "handoff", Type: workflowregistry.NodeTypeHandoffToHuman, Name: "Handoff"}, + }, + Edges: []dsl.Edge{{ID: "edge_start_handoff", Source: "start", Target: "handoff"}}, + }) + version := models.AIWorkflowVersion{ + WorkflowID: 1, + Version: 1, + Status: enums.StatusOk, + Definition: definitionJSON, + } + if err := db.Create(&version).Error; err != nil { + t.Fatalf("create workflow version: %v", err) + } + + agent, _, err := prepareWorkflowAgent(models.AIAgent{ + ID: 1, + SystemPrompt: "保持简洁回答。", + WorkflowVersionID: version.ID, + }) + if err != nil { + t.Fatalf("prepareWorkflowAgent() error = %v", err) + } + if agent.SystemPrompt != "保持简洁回答。" { + t.Fatalf("expected system prompt to stay unchanged, got %q", agent.SystemPrompt) + } +} + func TestServiceResumeUsesWorkflowCheckpointData(t *testing.T) { db := setupWorkflowResumeTestDB(t) def := runtimeHumanConfirmDefinition() diff --git a/internal/ai/workflow/compiler/compiler.go b/internal/ai/workflow/compiler/compiler.go deleted file mode 100644 index d49eafd..0000000 --- a/internal/ai/workflow/compiler/compiler.go +++ /dev/null @@ -1,60 +0,0 @@ -package compiler - -import ( - "fmt" - "strings" - - "agent-desk/internal/ai/workflow/dsl" - workflowregistry "agent-desk/internal/ai/workflow/registry" - "agent-desk/internal/pkg/toolx" -) - -type Result struct { - ToolCodes []string - Appendix string -} - -func Compile(def dsl.Definition) Result { - toolCodes := make([]string, 0) - lines := make([]string, 0, len(def.Nodes)+2) - if strings.TrimSpace(def.EntryNodeID) != "" { - lines = append(lines, fmt.Sprintf("Workflow entry node: %s.", strings.TrimSpace(def.EntryNodeID))) - } - for _, node := range def.Nodes { - nodeType := strings.TrimSpace(node.Type) - if code := graphToolCodeForNodeType(nodeType); code != "" { - toolCodes = append(toolCodes, code) - } - nodeName := strings.TrimSpace(node.Name) - if nodeName == "" { - nodeName = strings.TrimSpace(node.ID) - } - if nodeName == "" { - continue - } - lines = append(lines, fmt.Sprintf("- %s: %s", nodeName, nodeType)) - } - appendix := "" - if len(lines) > 0 { - appendix = "Published customer-service workflow:\n" + strings.Join(lines, "\n") - } - return Result{ - ToolCodes: toolx.NormalizeToolCodes(toolCodes), - Appendix: appendix, - } -} - -func graphToolCodeForNodeType(nodeType string) string { - switch strings.TrimSpace(nodeType) { - case workflowregistry.NodeTypeAnalyzeConversation: - return toolx.GraphAnalyzeConversation.Code - case workflowregistry.NodeTypePrepareTicketDraft: - return toolx.GraphPrepareTicketDraft.Code - case workflowregistry.NodeTypeCreateTicket: - return toolx.GraphCreateTicketConfirm.Code - case workflowregistry.NodeTypeHandoffToHuman: - return toolx.GraphHandoffConversation.Code - default: - return "" - } -} diff --git a/internal/ai/workflow/compiler/compiler_test.go b/internal/ai/workflow/compiler/compiler_test.go deleted file mode 100644 index f33d67c..0000000 --- a/internal/ai/workflow/compiler/compiler_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package compiler - -import ( - "testing" - - "agent-desk/internal/ai/workflow/dsl" - workflowregistry "agent-desk/internal/ai/workflow/registry" - "agent-desk/internal/pkg/toolx" -) - -func TestCompileMapsWorkflowNodesToGraphTools(t *testing.T) { - result := Compile(dsl.Definition{ - EntryNodeID: "start", - Nodes: []dsl.Node{ - {ID: "start", Type: workflowregistry.NodeTypeStart, Name: "Start"}, - {ID: "analyze", Type: workflowregistry.NodeTypeAnalyzeConversation, Name: "Analyze"}, - {ID: "draft", Type: workflowregistry.NodeTypePrepareTicketDraft, Name: "Draft"}, - {ID: "create", Type: workflowregistry.NodeTypeCreateTicket, Name: "Create"}, - {ID: "handoff", Type: workflowregistry.NodeTypeHandoffToHuman, Name: "Handoff"}, - }, - }) - want := []string{ - toolx.GraphAnalyzeConversation.Code, - toolx.GraphPrepareTicketDraft.Code, - toolx.GraphCreateTicketConfirm.Code, - toolx.GraphHandoffConversation.Code, - } - if len(result.ToolCodes) != len(want) { - t.Fatalf("expected %d tool codes, got %d: %#v", len(want), len(result.ToolCodes), result.ToolCodes) - } - for i, item := range want { - if result.ToolCodes[i] != item { - t.Fatalf("tool code[%d] = %s, want %s", i, result.ToolCodes[i], item) - } - } - if result.Appendix == "" { - t.Fatalf("expected workflow appendix") - } -} diff --git a/internal/handlers/dashboard/ai_agent_handler.go b/internal/handlers/dashboard/ai_agent_handler.go index 0f5d734..a81adc4 100644 --- a/internal/handlers/dashboard/ai_agent_handler.go +++ b/internal/handlers/dashboard/ai_agent_handler.go @@ -188,7 +188,6 @@ func buildAIAgentResponseWithLocale(item *models.AIAgent, locale string) respons Skills: make([]response.AIAgentSkillResponse, 0), Teams: make([]response.AIAgentTeamResponse, 0), DirectTools: make([]response.AIAgentMCPToolResponse, 0), - GraphTools: make([]string, 0), WorkflowVersionID: item.WorkflowVersionID, WorkflowPublished: item.WorkflowVersionID > 0, WorkflowState: aiAgentWorkflowState(item.WorkflowVersionID), @@ -236,7 +235,6 @@ func buildAIAgentResponseWithLocale(item *models.AIAgent, locale string) respons continue } if toolx.IsAgentDirectGraphToolCode(toolCode) { - ret.GraphTools = appendGraphToolCodeIfMissing(ret.GraphTools, toolCode) continue } serverCode := strings.TrimSpace(tool.ServerCode) @@ -271,18 +269,6 @@ func buildAIAgentResponseWithLocale(item *models.AIAgent, locale string) respons } } } - 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 } @@ -299,16 +285,3 @@ func aiAgentWorkflowStateText(workflowVersionID int64) string { } return "未发布" } - -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) -} diff --git a/internal/models/models.go b/internal/models/models.go index 30dbb85..e28fbe9 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -524,7 +524,6 @@ 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。 WorkflowVersionID int64 `gorm:"type:bigint;not null;default:0;index"` // WorkflowVersionID 为绑定的已发布会话流程版本ID。 SortNo int `gorm:"type:int;not null;default:0;index"` // SortNo 为后台展示排序号。 AuditFields diff --git a/internal/pkg/dto/request/ai_request.go b/internal/pkg/dto/request/ai_request.go index 35d5f0a..457f35d 100644 --- a/internal/pkg/dto/request/ai_request.go +++ b/internal/pkg/dto/request/ai_request.go @@ -57,7 +57,6 @@ type CreateAIAgentRequest struct { KnowledgeIDs []int64 `json:"knowledgeIds"` SkillIDs []int64 `json:"skillIds"` DirectTools []AIAgentMCPToolRequest `json:"directTools"` - GraphTools []string `json:"graphTools"` } type UpdateAIAgentRequest struct { diff --git a/internal/pkg/dto/response/ai_response.go b/internal/pkg/dto/response/ai_response.go index 7aad5d6..0ab19f3 100644 --- a/internal/pkg/dto/response/ai_response.go +++ b/internal/pkg/dto/response/ai_response.go @@ -90,7 +90,6 @@ type AIAgentResponse struct { SkillIDs []int64 `json:"skillIds"` Skills []AIAgentSkillResponse `json:"skills"` DirectTools []AIAgentMCPToolResponse `json:"directTools"` - GraphTools []string `json:"graphTools"` WorkflowVersionID int64 `json:"workflowVersionId"` WorkflowPublished bool `json:"workflowPublished"` WorkflowState string `json:"workflowState"` diff --git a/internal/services/ai_agent_service.go b/internal/services/ai_agent_service.go index 0eaf602..d91929c 100644 --- a/internal/services/ai_agent_service.go +++ b/internal/services/ai_agent_service.go @@ -113,7 +113,6 @@ 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, "update_user_id": operator.UserID, "update_user_name": operator.Username, "updated_at": time.Now(), @@ -193,10 +192,6 @@ 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) @@ -205,14 +200,6 @@ 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.InvalidParamI18n("error.e0028") - } - graphToolsJSON = string(buf) - } return &models.AIAgent{ Name: name, Description: strings.TrimSpace(req.Description), @@ -228,7 +215,6 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe KnowledgeIDs: utils.JoinInt64s(knowledgeIDs), SkillIDs: utils.JoinInt64s(skillIDs), AllowedMCPTools: directToolsJSON, - AllowedGraphTools: graphToolsJSON, WorkflowVersionID: 0, }, nil } @@ -333,29 +319,6 @@ 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.InvalidParamI18n("error.e0027") - } - 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 { diff --git a/web/app/dashboard/ai-agents/_components/config-workbench-copy.test.mjs b/web/app/dashboard/ai-agents/_components/config-workbench-copy.test.mjs index e068caf..59752fa 100644 --- a/web/app/dashboard/ai-agents/_components/config-workbench-copy.test.mjs +++ b/web/app/dashboard/ai-agents/_components/config-workbench-copy.test.mjs @@ -4,6 +4,8 @@ import { readFile } from "node:fs/promises" const configWorkbenchSource = await readFile(new URL("./config-workbench.tsx", import.meta.url), "utf8") const zhMessagesSource = await readFile(new URL("../../../../messages/zh-CN.json", import.meta.url), "utf8") +const adminApiSource = await readFile(new URL("../../../../lib/api/admin.ts", import.meta.url), "utf8") +const zhMessages = JSON.parse(zhMessagesSource) test("AI Agent workflow-era policy copy separates handoff execution from knowledge fallback", () => { const combinedSource = `${configWorkbenchSource}\n${zhMessagesSource}` @@ -19,3 +21,13 @@ test("AI Agent workflow-era policy copy separates handoff execution from knowled assert.doesNotMatch(configWorkbenchSource, /兜底策略/) assert.doesNotMatch(configWorkbenchSource, /兜底文案/) }) + +test("AI Agent config no longer exposes legacy graph tool routing knobs", () => { + const aiAgentMessages = JSON.stringify(zhMessages.aiAgent ?? {}) + + assert.doesNotMatch(configWorkbenchSource, /graphTools/) + assert.doesNotMatch(adminApiSource, /graphTools/) + assert.doesNotMatch(aiAgentMessages, /graphTools/) + assert.doesNotMatch(aiAgentMessages, /Graph Tool/) + assert.doesNotMatch(aiAgentMessages, /内置流程/) +}) diff --git a/web/app/dashboard/ai-agents/_components/config-workbench.tsx b/web/app/dashboard/ai-agents/_components/config-workbench.tsx index 9337539..3b76e45 100644 --- a/web/app/dashboard/ai-agents/_components/config-workbench.tsx +++ b/web/app/dashboard/ai-agents/_components/config-workbench.tsx @@ -396,7 +396,6 @@ export function AIAgentConfigWorkbench({ knowledgeIds: uniqueNumbers(selectedKnowledgeIds), skillIds: uniqueNumbers(selectedSkillIds), directTools, - graphTools: [], } } diff --git a/web/lib/api/admin.ts b/web/lib/api/admin.ts index 354906d..0ad08e2 100644 --- a/web/lib/api/admin.ts +++ b/web/lib/api/admin.ts @@ -239,7 +239,6 @@ export type AIAgent = { description: string arguments?: Record }[] - graphTools: string[] workflowVersionId: number workflowPublished: boolean workflowState: string @@ -273,7 +272,6 @@ export type CreateAIAgentPayload = { description: string arguments?: Record }[] - graphTools: string[] } export type UpdateAIAgentPayload = CreateAIAgentPayload & { diff --git a/web/messages/en-US.json b/web/messages/en-US.json index 7d0e684..40ec735 100644 --- a/web/messages/en-US.json +++ b/web/messages/en-US.json @@ -1090,7 +1090,6 @@ "knowledgeTab": "Knowledge", "skillsTab": "Skills", "directToolsTab": "MCP tools", - "graphToolsTab": "Graph Tools", "knowledgeHint": "Select at least one knowledge base. You can adjust priority order.", "selectKnowledge": "Select and add knowledge base", "searchKnowledge": "Search knowledge bases", @@ -1117,13 +1116,7 @@ "searchDirectTool": "Search Direct Tools", "emptyDirectTool": "No Direct Tools available", "noDirectToolsHint": "Without Direct Tools, the agent will not call external or built-in tools directly. It will rely on knowledge bases, skills, and normal replies.", - "removeDirectTool": "Remove Direct Tool {name}", - "graphToolsHint": "Use for built-in workflows such as ticket creation and human handoff. These are kept separate from Direct Tools.", - "selectGraphTool": "Select Graph Tool", - "searchGraphTool": "Search Graph Tools", - "emptyGraphTool": "No Graph Tools available", - "noGraphToolsHint": "Without Graph Tools, the agent will not expose built-in workflow tools such as ticket creation or human handoff.", - "removeGraphTool": "Remove Graph Tool {name}" + "removeDirectTool": "Remove Direct Tool {name}" }, "aiConfig": { "allStatuses": "All statuses", diff --git a/web/messages/zh-CN.json b/web/messages/zh-CN.json index b3c8a98..710f7bf 100644 --- a/web/messages/zh-CN.json +++ b/web/messages/zh-CN.json @@ -1090,7 +1090,6 @@ "knowledgeTab": "知识库", "skillsTab": "Skills", "directToolsTab": "MCP tools", - "graphToolsTab": "内置流程", "knowledgeHint": "至少选择一个知识库,可调整知识库优先级。", "selectKnowledge": "选择并添加知识库", "searchKnowledge": "搜索知识库", @@ -1117,13 +1116,7 @@ "searchDirectTool": "搜索 Direct Tool", "emptyDirectTool": "没有可添加的 Direct Tool", "noDirectToolsHint": "不配置 Direct Tool 时,Agent 不会直接调用外部或内置工具,只会依赖知识库、Skill 和普通回复。", - "removeDirectTool": "移除 Direct Tool {name}", - "graphToolsHint": "用于建单、转人工等系统内置流程,不再混放到 Direct Tools 中。", - "selectGraphTool": "选择 Graph Tool", - "searchGraphTool": "搜索 Graph Tool", - "emptyGraphTool": "没有可添加的 Graph Tool", - "noGraphToolsHint": "不配置 Graph Tool 时,Agent 不会暴露建单/转人工等内置流程工具。", - "removeGraphTool": "移除 Graph Tool {name}" + "removeDirectTool": "移除 Direct Tool {name}" }, "aiConfig": { "allStatuses": "全部状态",