refactor: 将客服后端重构为宿主可嵌入模块
- 注入数据库、运行时配置、统一响应、文件存储和平台 AI 能力,补充业务读写工具与客户快捷操作契约。 - 移除模块内重复的组织、客户、工单、标签、技能、旧工作流、MCP 和迁移实现,将身份权限与业务主体交由宿主管理。 - 使用 libSQL 重构向量存储,并完善图片消息、访客身份、排队调度、企业微信和支持聊天页面。 - 统一 HTTP、DTO 与 WebSocket 的 snake_case 协议,补齐模块初始化、业务动作和公共载荷等回归测试。
This commit is contained in:
@@ -38,62 +38,50 @@ func (s *agentRevisionService) FindByAgentID(agentID int64) []models.AgentRevisi
|
||||
}
|
||||
|
||||
type agentRevisionDefinition struct {
|
||||
Agent agentRevisionAgent `json:"agent"`
|
||||
Model agentRevisionModel `json:"model"`
|
||||
WorkflowBindings []AgentRevisionWorkflowBinding `json:"workflowBindings"`
|
||||
}
|
||||
|
||||
type AgentRevisionWorkflowBinding struct {
|
||||
WorkflowID int64 `json:"workflowId"`
|
||||
WorkflowVersionID int64 `json:"workflowVersionId"`
|
||||
ToolName string `json:"toolName"`
|
||||
TriggerInstruction string `json:"triggerInstruction"`
|
||||
Priority int `json:"priority"`
|
||||
Agent agentRevisionAgent `json:"agent"`
|
||||
Model agentRevisionModel `json:"model"`
|
||||
}
|
||||
|
||||
// agentRevisionModel deliberately excludes APIKey. A revision must capture
|
||||
// reproducible routing/model parameters without duplicating credentials.
|
||||
type agentRevisionModel struct {
|
||||
ConfigID int64 `json:"configId"`
|
||||
ConfigID int64 `json:"config_id"`
|
||||
Provider string `json:"provider"`
|
||||
BaseURL string `json:"baseUrl"`
|
||||
ModelType string `json:"modelType"`
|
||||
ModelName string `json:"modelName"`
|
||||
MaxContextTokens int `json:"maxContextTokens"`
|
||||
MaxOutputTokens int `json:"maxOutputTokens"`
|
||||
TimeoutMS int `json:"timeoutMs"`
|
||||
MaxRetryCount int `json:"maxRetryCount"`
|
||||
BaseURL string `json:"base_url"`
|
||||
ModelType string `json:"model_type"`
|
||||
ModelName string `json:"model_name"`
|
||||
MaxContextTokens int `json:"max_context_tokens"`
|
||||
MaxOutputTokens int `json:"max_output_tokens"`
|
||||
TimeoutMS int `json:"timeout_ms"`
|
||||
MaxRetryCount int `json:"max_retry_count"`
|
||||
}
|
||||
|
||||
type agentRevisionAgent struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
AIConfigID int64 `json:"aiConfigId"`
|
||||
MaxSteps int `json:"maxSteps"`
|
||||
ContextWindow int `json:"contextWindow"`
|
||||
ToolPolicy string `json:"toolPolicy"`
|
||||
KnowledgePolicy string `json:"knowledgePolicy"`
|
||||
ServiceMode int `json:"serviceMode"`
|
||||
SystemPrompt string `json:"systemPrompt"`
|
||||
WelcomeMessage string `json:"welcomeMessage"`
|
||||
ReplyTimeoutSeconds int `json:"replyTimeoutSeconds"`
|
||||
TeamIDs string `json:"teamIds"`
|
||||
HandoffMode int `json:"handoffMode"`
|
||||
FallbackMode int `json:"fallbackMode"`
|
||||
FallbackMessage string `json:"fallbackMessage"`
|
||||
KnowledgeIDs string `json:"knowledgeIds"`
|
||||
SkillIDs string `json:"skillIds"`
|
||||
AllowedMCPTools string `json:"allowedMcpTools"`
|
||||
AIConfigID int64 `json:"ai_config_id"`
|
||||
MaxSteps int `json:"max_steps"`
|
||||
ContextWindow int `json:"context_window"`
|
||||
ToolPolicy string `json:"tool_policy"`
|
||||
KnowledgePolicy string `json:"knowledge_policy"`
|
||||
ServiceMode int `json:"service_mode"`
|
||||
SystemPrompt string `json:"system_prompt"`
|
||||
WelcomeMessage string `json:"welcome_message"`
|
||||
ReplyTimeoutSeconds int `json:"reply_timeout_seconds"`
|
||||
TeamIDs string `json:"team_ids"`
|
||||
HandoffMode int `json:"handoff_mode"`
|
||||
FallbackMode int `json:"fallback_mode"`
|
||||
FallbackMessage string `json:"fallback_message"`
|
||||
KnowledgeIDs string `json:"knowledge_ids"`
|
||||
}
|
||||
|
||||
// AgentRevisionSnapshot is the immutable runtime configuration restored from
|
||||
// a published revision. Model credentials deliberately remain on the current
|
||||
// AIConfig so credential rotation does not require republishing every Agent.
|
||||
type AgentRevisionSnapshot struct {
|
||||
Revision models.AgentRevision
|
||||
Agent models.AIAgent
|
||||
AIConfig models.AIConfig
|
||||
WorkflowBindings []AgentRevisionWorkflowBinding
|
||||
Revision models.AgentRevision
|
||||
Agent models.AIAgent
|
||||
AIConfig models.AIConfig
|
||||
}
|
||||
|
||||
// ResolvePublishedSnapshot restores an immutable published Agent revision.
|
||||
@@ -117,7 +105,7 @@ func (s *agentRevisionService) ResolvePublishedSnapshot(agent models.AIAgent, co
|
||||
if publishedConfigID <= 0 {
|
||||
publishedConfigID = definition.Model.ConfigID
|
||||
}
|
||||
if publishedConfigID > 0 && publishedConfigID != config.ID {
|
||||
if !config.Platform && publishedConfigID > 0 && publishedConfigID != config.ID {
|
||||
publishedConfig := repositories.AIConfigRepository.Get(sqls.DB(), publishedConfigID)
|
||||
if publishedConfig == nil || publishedConfig.Status != enums.StatusOk {
|
||||
return nil, errorsx.InvalidParam("published agent model config is unavailable")
|
||||
@@ -125,8 +113,9 @@ func (s *agentRevisionService) ResolvePublishedSnapshot(agent models.AIAgent, co
|
||||
snapshot.AIConfig = *publishedConfig
|
||||
}
|
||||
applyRevisionAgentSnapshot(&snapshot.Agent, definition.Agent)
|
||||
snapshot.WorkflowBindings = append([]AgentRevisionWorkflowBinding(nil), definition.WorkflowBindings...)
|
||||
applyRevisionModelSnapshot(&snapshot.AIConfig, definition.Model)
|
||||
if !config.Platform {
|
||||
applyRevisionModelSnapshot(&snapshot.AIConfig, definition.Model)
|
||||
}
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
@@ -150,8 +139,6 @@ func applyRevisionAgentSnapshot(agent *models.AIAgent, definition agentRevisionA
|
||||
agent.FallbackMode = enums.AIAgentFallbackMode(definition.FallbackMode)
|
||||
agent.FallbackMessage = definition.FallbackMessage
|
||||
agent.KnowledgeIDs = definition.KnowledgeIDs
|
||||
agent.SkillIDs = definition.SkillIDs
|
||||
agent.AllowedMCPTools = definition.AllowedMCPTools
|
||||
}
|
||||
|
||||
func applyRevisionModelSnapshot(config *models.AIConfig, definition agentRevisionModel) {
|
||||
@@ -188,13 +175,9 @@ func (s *agentRevisionService) publishSnapshot(db *gorm.DB, agent *models.AIAgen
|
||||
ToolPolicy: agent.ToolPolicy, KnowledgePolicy: agent.KnowledgePolicy, ServiceMode: int(agent.ServiceMode), SystemPrompt: agent.SystemPrompt,
|
||||
WelcomeMessage: agent.WelcomeMessage, ReplyTimeoutSeconds: agent.ReplyTimeoutSeconds, TeamIDs: agent.TeamIDs, HandoffMode: int(agent.HandoffMode),
|
||||
FallbackMode: int(agent.FallbackMode), FallbackMessage: agent.FallbackMessage, KnowledgeIDs: agent.KnowledgeIDs,
|
||||
SkillIDs: agent.SkillIDs, AllowedMCPTools: agent.AllowedMCPTools,
|
||||
},
|
||||
Model: model,
|
||||
}
|
||||
for _, binding := range repositories.AIAgentWorkflowBindingRepository.FindEnabledByAgentID(db, agent.ID) {
|
||||
definition.WorkflowBindings = append(definition.WorkflowBindings, AgentRevisionWorkflowBinding{WorkflowID: binding.WorkflowID, WorkflowVersionID: binding.WorkflowVersionID, ToolName: binding.ToolName, TriggerInstruction: binding.TriggerInstruction, Priority: binding.Priority})
|
||||
}
|
||||
data, err := json.Marshal(definition)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user