diff --git a/internal/ai/application/runtime/tool_catalog_test.go b/internal/ai/application/runtime/tool_catalog_test.go index 70bab59..812fcea 100644 --- a/internal/ai/application/runtime/tool_catalog_test.go +++ b/internal/ai/application/runtime/tool_catalog_test.go @@ -125,7 +125,7 @@ func TestPrepareWorkflowAgentRejectsMissingPublishedWorkflow(t *testing.T) { if err == nil { t.Fatalf("expected missing workflow version error") } - if !strings.Contains(err.Error(), "workflow version is required") { + if !strings.Contains(err.Error(), "AI Agent workflow is not published") { t.Fatalf("unexpected error: %v", err) } } diff --git a/internal/ai/application/runtime/workflow_runtime.go b/internal/ai/application/runtime/workflow_runtime.go index fe5466c..470923b 100644 --- a/internal/ai/application/runtime/workflow_runtime.go +++ b/internal/ai/application/runtime/workflow_runtime.go @@ -23,7 +23,7 @@ type resolvedWorkflow struct { func resolveAgentWorkflow(aiAgent models.AIAgent) (resolvedWorkflow, error) { if aiAgent.WorkflowVersionID <= 0 { - return resolvedWorkflow{}, errorsx.InvalidParam("workflow version is required") + return resolvedWorkflow{}, errorsx.InvalidParam("AI Agent workflow is not published; publish a workflow version before enabling automatic replies") } version := repositories.AIWorkflowVersionRepository.Get(sqls.DB(), aiAgent.WorkflowVersionID) if version == nil || version.Status != enums.StatusOk { diff --git a/internal/handlers/dashboard/ai_agent_handler.go b/internal/handlers/dashboard/ai_agent_handler.go index ede701a..0f5d734 100644 --- a/internal/handlers/dashboard/ai_agent_handler.go +++ b/internal/handlers/dashboard/ai_agent_handler.go @@ -190,6 +190,9 @@ func buildAIAgentResponseWithLocale(item *models.AIAgent, locale string) respons DirectTools: make([]response.AIAgentMCPToolResponse, 0), GraphTools: make([]string, 0), WorkflowVersionID: item.WorkflowVersionID, + WorkflowPublished: item.WorkflowVersionID > 0, + WorkflowState: aiAgentWorkflowState(item.WorkflowVersionID), + WorkflowStateText: aiAgentWorkflowStateText(item.WorkflowVersionID), SortNo: item.SortNo, CreatedAt: item.CreatedAt.Format("2006-01-02 15:04:05"), UpdatedAt: item.UpdatedAt.Format("2006-01-02 15:04:05"), @@ -283,6 +286,20 @@ func buildAIAgentResponseWithLocale(item *models.AIAgent, locale string) respons return ret } +func aiAgentWorkflowState(workflowVersionID int64) string { + if workflowVersionID > 0 { + return "published" + } + return "draft" +} + +func aiAgentWorkflowStateText(workflowVersionID int64) string { + if workflowVersionID > 0 { + return "已发布" + } + return "未发布" +} + func appendGraphToolCodeIfMissing(items []string, toolCode string) []string { toolCode = strings.TrimSpace(toolCode) if toolCode == "" { diff --git a/internal/handlers/dashboard/ai_agent_handler_test.go b/internal/handlers/dashboard/ai_agent_handler_test.go new file mode 100644 index 0000000..27ebbf7 --- /dev/null +++ b/internal/handlers/dashboard/ai_agent_handler_test.go @@ -0,0 +1,63 @@ +package dashboard + +import ( + "testing" + + "agent-desk/internal/models" + + "github.com/glebarez/sqlite" + "github.com/mlogclub/simple/sqls" + "gorm.io/gorm" +) + +func TestBuildAIAgentResponseExposesWorkflowPublishState(t *testing.T) { + setupAIAgentHandlerTestDB(t) + + draft := buildAIAgentResponse(&models.AIAgent{}) + if draft.WorkflowPublished { + t.Fatalf("draft.WorkflowPublished = true, want false") + } + if draft.WorkflowState != "draft" { + t.Fatalf("draft.WorkflowState = %q, want draft", draft.WorkflowState) + } + if draft.WorkflowStateText == "" { + t.Fatalf("expected draft workflow state text") + } + + published := buildAIAgentResponse(&models.AIAgent{WorkflowVersionID: 12}) + if !published.WorkflowPublished { + t.Fatalf("published.WorkflowPublished = false, want true") + } + if published.WorkflowState != "published" { + t.Fatalf("published.WorkflowState = %q, want published", published.WorkflowState) + } + if published.WorkflowStateText == "" { + t.Fatalf("expected published workflow state text") + } +} + +func setupAIAgentHandlerTestDB(t *testing.T) { + t.Helper() + db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) + if err != nil { + t.Fatalf("open sqlite db: %v", err) + } + sqlDB, err := db.DB() + if err != nil { + t.Fatalf("get sqlite db: %v", err) + } + t.Cleanup(func() { + if err := sqlDB.Close(); err != nil { + t.Fatalf("close sqlite db: %v", err) + } + }) + if err := db.AutoMigrate( + &models.AIConfig{}, + &models.AgentTeam{}, + &models.KnowledgeBase{}, + &models.SkillDefinition{}, + ); err != nil { + t.Fatalf("auto migrate: %v", err) + } + sqls.SetDB(db) +} diff --git a/internal/pkg/dto/response/ai_response.go b/internal/pkg/dto/response/ai_response.go index cc7ca62..7aad5d6 100644 --- a/internal/pkg/dto/response/ai_response.go +++ b/internal/pkg/dto/response/ai_response.go @@ -92,6 +92,9 @@ type AIAgentResponse struct { DirectTools []AIAgentMCPToolResponse `json:"directTools"` GraphTools []string `json:"graphTools"` WorkflowVersionID int64 `json:"workflowVersionId"` + WorkflowPublished bool `json:"workflowPublished"` + WorkflowState string `json:"workflowState"` + WorkflowStateText string `json:"workflowStateText"` SortNo int `json:"sortNo"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` diff --git a/web/app/dashboard/ai-agents/_components/config-workbench.tsx b/web/app/dashboard/ai-agents/_components/config-workbench.tsx index 3d7806b..17153b8 100644 --- a/web/app/dashboard/ai-agents/_components/config-workbench.tsx +++ b/web/app/dashboard/ai-agents/_components/config-workbench.tsx @@ -160,6 +160,10 @@ function uniqueNumbers(input: number[]) { return Array.from(new Set(input.filter((id) => Number.isFinite(id) && id > 0))) } +function isWorkflowPublished(agent: AIAgent | null) { + return Boolean(agent?.workflowPublished ?? (agent?.workflowVersionId ?? 0) > 0) +} + export function AIAgentConfigWorkbench({ agentId, onAgentSaved, @@ -544,6 +548,9 @@ export function AIAgentConfigWorkbench({ const selectedKnowledgeOptions = selectedOptions(selectedKnowledgeIds, knowledgeOptions) const selectedTeamOptions = selectedOptions(selectedTeamIds, teamOptions) const selectedSkillOptions = selectedOptions(selectedSkillIds, skillOptions) + const workflowPublished = isWorkflowPublished(agent) + const workflowStateText = + agent?.workflowStateText || (workflowPublished ? "已发布" : "未发布") return (