refactor: 将客服后端重构为宿主可嵌入模块
- 注入数据库、运行时配置、统一响应、文件存储和平台 AI 能力,补充业务读写工具与客户快捷操作契约。 - 移除模块内重复的组织、客户、工单、标签、技能、旧工作流、MCP 和迁移实现,将身份权限与业务主体交由宿主管理。 - 使用 libSQL 重构向量存储,并完善图片消息、访客身份、排队调度、企业微信和支持聊天页面。 - 统一 HTTP、DTO 与 WebSocket 的 snake_case 协议,补齐模块初始化、业务动作和公共载荷等回归测试。
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.tczkiot.com/wlw/ai-agent/internal/ai/workflow/dsl"
|
||||
workflowregistry "code.tczkiot.com/wlw/ai-agent/internal/ai/workflow/registry"
|
||||
"code.tczkiot.com/wlw/ai-agent/internal/models"
|
||||
"code.tczkiot.com/wlw/ai-agent/internal/pkg/dto/request"
|
||||
"code.tczkiot.com/wlw/ai-agent/internal/pkg/enums"
|
||||
@@ -27,51 +23,6 @@ func TestBuildKnowledgeBaseModelUsesLowerDefaultScoreThreshold(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteKnowledgeBaseRejectsWorkflowDraftReference(t *testing.T) {
|
||||
setupKnowledgeBaseServiceTestDB(t)
|
||||
kb := createKnowledgeBaseServiceTestBase(t, "Referenced KB")
|
||||
otherKB := createKnowledgeBaseServiceTestBase(t, "Other KB")
|
||||
createKnowledgeBaseServiceTestWorkflow(t, "Support Workflow", knowledgeBaseServiceTestWorkflowDefinition([]int64{12, otherKB.ID}))
|
||||
createKnowledgeBaseServiceTestWorkflow(t, "Knowledge Workflow", knowledgeBaseServiceTestWorkflowDefinition([]int64{12, kb.ID, otherKB.ID}))
|
||||
|
||||
err := KnowledgeBaseService.DeleteKnowledgeBase(kb.ID)
|
||||
if err == nil {
|
||||
t.Fatal("DeleteKnowledgeBase() error is nil, want referenced workflow error")
|
||||
}
|
||||
if got := err.Error(); !strings.Contains(got, "Knowledge Workflow") {
|
||||
t.Fatalf("DeleteKnowledgeBase() error = %q, want workflow name", got)
|
||||
}
|
||||
if repositories.KnowledgeBaseRepository.Get(sqls.DB(), kb.ID) == nil {
|
||||
t.Fatal("knowledge base was deleted despite workflow reference")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteKnowledgeBaseRejectsWorkflowVersionReference(t *testing.T) {
|
||||
setupKnowledgeBaseServiceTestDB(t)
|
||||
kb := createKnowledgeBaseServiceTestBase(t, "Version KB")
|
||||
workflow := createKnowledgeBaseServiceTestWorkflow(t, "Published Workflow", knowledgeBaseServiceTestWorkflowDefinition([]int64{999}))
|
||||
raw, err := json.Marshal(knowledgeBaseServiceTestWorkflowDefinition([]int64{kb.ID}))
|
||||
if err != nil {
|
||||
t.Fatalf("marshal workflow version definition: %v", err)
|
||||
}
|
||||
if err := repositories.AIWorkflowVersionRepository.Create(sqls.DB(), &models.AIWorkflowVersion{
|
||||
WorkflowID: workflow.ID,
|
||||
Version: 1,
|
||||
Status: enums.StatusOk,
|
||||
Definition: string(raw),
|
||||
}); err != nil {
|
||||
t.Fatalf("create workflow version: %v", err)
|
||||
}
|
||||
|
||||
err = KnowledgeBaseService.DeleteKnowledgeBase(kb.ID)
|
||||
if err == nil {
|
||||
t.Fatal("DeleteKnowledgeBase() error is nil, want referenced workflow version error")
|
||||
}
|
||||
if got := err.Error(); !strings.Contains(got, "Published Workflow") {
|
||||
t.Fatalf("DeleteKnowledgeBase() error = %q, want workflow name", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteKnowledgeBaseCascadesContentWhenNotReferenced(t *testing.T) {
|
||||
setupKnowledgeBaseServiceTestDB(t)
|
||||
kb := createKnowledgeBaseServiceTestBase(t, "Delete KB")
|
||||
@@ -119,67 +70,12 @@ func setupKnowledgeBaseServiceTestDB(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("open sqlite db: %v", err)
|
||||
}
|
||||
if err := db.AutoMigrate(&models.KnowledgeBase{}, &models.KnowledgeDocument{}, &models.KnowledgeFAQ{}, &models.KnowledgeChunk{}, &models.AIAgent{}, &models.AIWorkflow{}, &models.AIWorkflowVersion{}); err != nil {
|
||||
if err := db.AutoMigrate(&models.KnowledgeBase{}, &models.KnowledgeDocument{}, &models.KnowledgeFAQ{}, &models.KnowledgeChunk{}, &models.AIAgent{}); err != nil {
|
||||
t.Fatalf("auto migrate: %v", err)
|
||||
}
|
||||
sqls.SetDB(db)
|
||||
}
|
||||
|
||||
func createKnowledgeBaseServiceTestWorkflow(t *testing.T, name string, definition dsl.Definition) *models.AIWorkflow {
|
||||
t.Helper()
|
||||
raw, err := json.Marshal(definition)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal workflow definition: %v", err)
|
||||
}
|
||||
item := &models.AIWorkflow{
|
||||
Name: name,
|
||||
Status: enums.StatusOk,
|
||||
DraftDefinition: string(raw),
|
||||
}
|
||||
if err := repositories.AIWorkflowRepository.Create(sqls.DB(), item); err != nil {
|
||||
t.Fatalf("create workflow: %v", err)
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func knowledgeBaseServiceTestWorkflowDefinition(knowledgeBaseIDs []int64) dsl.Definition {
|
||||
return dsl.Definition{
|
||||
SchemaVersion: dsl.SchemaVersion,
|
||||
Nodes: []dsl.Node{
|
||||
{
|
||||
ID: "start_1",
|
||||
Type: workflowregistry.NodeTypeStart,
|
||||
},
|
||||
{
|
||||
ID: "retrieve_1",
|
||||
Type: workflowregistry.NodeTypeKnowledgeRetrieve,
|
||||
Data: dsl.NodeData{
|
||||
Config: mustKnowledgeBaseServiceTestJSON(map[string]any{"knowledgeBaseIds": knowledgeBaseIDs}),
|
||||
InputsValues: map[string]dsl.Value{
|
||||
"query": dsl.RefValue("start_1", "userMessage"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "end_1",
|
||||
Type: workflowregistry.NodeTypeEnd,
|
||||
},
|
||||
},
|
||||
Edges: []dsl.Edge{
|
||||
{SourceNodeID: "start_1", TargetNodeID: "retrieve_1"},
|
||||
{SourceNodeID: "retrieve_1", TargetNodeID: "end_1"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func mustKnowledgeBaseServiceTestJSON(value any) json.RawMessage {
|
||||
raw, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
func createKnowledgeBaseServiceTestBase(t *testing.T, name string) *models.KnowledgeBase {
|
||||
t.Helper()
|
||||
item := &models.KnowledgeBase{
|
||||
|
||||
Reference in New Issue
Block a user