feat: enhance variable handling and UI components with business labels and descriptions
This commit is contained in:
@@ -28,11 +28,11 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "PlayCircleIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
OutputSchema: []VariableSpec{
|
||||
output("conversationId", VariableTypeInteger, "Conversation ID."),
|
||||
output("messageId", VariableTypeInteger, "Current user message ID."),
|
||||
output("aiAgentId", VariableTypeInteger, "AI Agent ID."),
|
||||
output("userMessage", VariableTypeString, "Current user message content."),
|
||||
output("knowledgeBaseIds", VariableTypeIntegerArray, "Knowledge bases bound to the AI Agent."),
|
||||
output("conversationId", "会话 ID", VariableTypeInteger, "当前客户会话的内部编号。"),
|
||||
output("messageId", "消息 ID", VariableTypeInteger, "客户本轮消息的内部编号。"),
|
||||
output("aiAgentId", "AI Agent ID", VariableTypeInteger, "当前处理会话的 AI Agent 编号。"),
|
||||
output("userMessage", "用户消息", VariableTypeString, "客户本轮发送的原始消息内容。"),
|
||||
output("knowledgeBaseIds", "知识库 ID 列表", VariableTypeIntegerArray, "当前 AI Agent 已绑定的知识库编号列表。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -42,11 +42,11 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "MessageCircleIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("userMessage", VariableTypeString, "Current user message content."),
|
||||
requiredInput("userMessage", "用户消息", VariableTypeString, "客户本轮发送的原始消息内容。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("normalizedMessage", VariableTypeString, "Normalized customer message."),
|
||||
enumOutput("messageIntent", "消息意图", "Detected customer message intent.", []VariableValueOption{
|
||||
output("normalizedMessage", "规范化消息", VariableTypeString, "经过清洗和规范化后的客户消息。"),
|
||||
enumOutput("messageIntent", "消息意图", "客户消息的意图分类。", []VariableValueOption{
|
||||
valueOption("unknown", "未知意图", "系统暂时无法判断客户意图。"),
|
||||
valueOption("greeting", "打招呼", "客户在问候或开始对话。"),
|
||||
valueOption("thanks", "表达感谢", "客户在表示感谢。"),
|
||||
@@ -58,16 +58,16 @@ func DefaultRegistry() *Registry {
|
||||
valueOption("ambiguous_question", "问题不明确", "客户问题缺少必要上下文,需要追问。"),
|
||||
valueOption("business_question", "业务问题", "客户问题适合进入知识库检索。"),
|
||||
}),
|
||||
enumOutput("answerScope", "回复策略", "Recommended answer scope.", []VariableValueOption{
|
||||
enumOutput("answerScope", "回复策略", "系统建议采用的回复处理范围。", []VariableValueOption{
|
||||
valueOption("direct_reply", "直接回复客户", "无需检索知识库或转人工,可以直接生成回复。"),
|
||||
valueOption("needs_clarification", "追问补充信息", "当前信息不足,需要客户补充。"),
|
||||
valueOption("needs_handoff", "转人工处理", "需要人工客服介入。"),
|
||||
valueOption("needs_ticket", "创建工单", "需要进入工单处理流程。"),
|
||||
valueOption("needs_knowledge", "检索知识库", "需要先检索知识库再回答。"),
|
||||
}),
|
||||
output("confidence", VariableTypeNumber, "Classifier confidence."),
|
||||
output("riskSignals", VariableTypeStringArray, "Detected risk signals."),
|
||||
output("reason", VariableTypeString, "Decision reason."),
|
||||
output("confidence", "置信度", VariableTypeNumber, "意图和回复策略判断的置信度。"),
|
||||
output("riskSignals", "风险信号", VariableTypeStringArray, "识别到的投诉、升级、人工介入等风险线索。"),
|
||||
output("reason", "判断原因", VariableTypeString, "本次意图和回复策略判断的原因说明。"),
|
||||
},
|
||||
DefaultInputs: map[string]dsl.Value{
|
||||
"userMessage": dsl.RefValue("start_1", "userMessage"),
|
||||
@@ -80,14 +80,14 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "ShieldCheckIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("messageIntent", VariableTypeString, "Detected customer message intent."),
|
||||
requiredInput("answerScope", VariableTypeString, "Recommended answer scope."),
|
||||
optionalInput("userMessage", VariableTypeString, "Current user message content."),
|
||||
optionalInput("riskSignals", VariableTypeStringArray, "Detected risk signals."),
|
||||
optionalInput("answerability", VariableTypeString, "Knowledge answerability decision."),
|
||||
requiredInput("messageIntent", "消息意图", VariableTypeString, "上游理解节点识别出的客户消息意图。"),
|
||||
requiredInput("answerScope", "回复策略", VariableTypeString, "上游理解节点建议采用的回复处理范围。"),
|
||||
optionalInput("userMessage", "用户消息", VariableTypeString, "客户本轮发送的原始消息内容。"),
|
||||
optionalInput("riskSignals", "风险信号", VariableTypeStringArray, "上游识别到的风险线索列表。"),
|
||||
optionalInput("answerability", "可回答性", VariableTypeString, "知识库结果是否足够支撑回答的判断。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
enumOutput("action", "处理策略", "Selected policy action.", []VariableValueOption{
|
||||
enumOutput("action", "处理策略", "回复策略节点选择的下一步处理动作。", []VariableValueOption{
|
||||
valueOption("direct_reply", "直接回复客户", "直接发送策略节点生成的回复。"),
|
||||
valueOption("clarify", "追问补充信息", "先让客户补充必要信息。"),
|
||||
valueOption("end_conversation", "结束会话", "发送结束语并结束本轮处理。"),
|
||||
@@ -96,15 +96,15 @@ func DefaultRegistry() *Registry {
|
||||
valueOption("retrieve_knowledge", "检索知识库", "进入知识检索和 AI 回复流程。"),
|
||||
valueOption("knowledge_fallback", "知识库兜底", "知识库结果不足,发送兜底回复。"),
|
||||
}),
|
||||
output("replyText", VariableTypeString, "Customer-visible reply text when the policy can answer directly."),
|
||||
output("reason", VariableTypeString, "Policy decision reason."),
|
||||
output("requiresFlow", VariableTypeBoolean, "Whether the decision should continue into workflow actions."),
|
||||
enumOutput("targetFlow", "目标流程", "Suggested target flow.", []VariableValueOption{
|
||||
output("replyText", "回复内容", VariableTypeString, "可直接发送给客户的回复文本。"),
|
||||
output("reason", "策略原因", VariableTypeString, "选择当前处理策略的原因说明。"),
|
||||
output("requiresFlow", "需要继续流程", VariableTypeBoolean, "是否需要继续执行后续工作流节点。"),
|
||||
enumOutput("targetFlow", "目标流程", "建议继续执行的业务流程。", []VariableValueOption{
|
||||
valueOption("handoff_to_human", "转人工流程", "继续执行转人工节点。"),
|
||||
valueOption("prepare_ticket", "工单流程", "继续执行工单草稿和确认节点。"),
|
||||
valueOption("knowledge", "知识库流程", "继续执行知识检索节点。"),
|
||||
}),
|
||||
enumOutput("finalReplySource", "回复来源", "Source category for the final reply.", []VariableValueOption{
|
||||
enumOutput("finalReplySource", "回复来源", "最终回复内容的来源类别。", []VariableValueOption{
|
||||
valueOption("direct_reply", "策略直接回复", "由回复策略节点直接生成回复。"),
|
||||
valueOption("clarification", "追问回复", "用于追问客户补充信息。"),
|
||||
valueOption("handoff_notice", "转人工提示", "用于提示客户已进入人工处理。"),
|
||||
@@ -121,11 +121,11 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "BookOpenIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("query", VariableTypeString, "Search query."),
|
||||
requiredInput("query", "检索问题", VariableTypeString, "用于检索知识库的客户问题或查询文本。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("items", VariableTypeObjectArray, "Retrieved knowledge items."),
|
||||
output("summary", VariableTypeString, "Short retrieval summary."),
|
||||
output("items", "知识条目", VariableTypeObjectArray, "从知识库命中的原始知识条目列表。"),
|
||||
output("summary", "检索摘要", VariableTypeString, "对本次知识检索结果的简短摘要。"),
|
||||
},
|
||||
DefaultInputs: map[string]dsl.Value{
|
||||
"query": dsl.RefValue("start_1", "userMessage"),
|
||||
@@ -138,15 +138,15 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "HelpCircleIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("userMessage", VariableTypeString, "Current user message content."),
|
||||
requiredInput("knowledgeItems", VariableTypeObjectArray, "Retrieved knowledge items."),
|
||||
requiredInput("userMessage", "用户消息", VariableTypeString, "客户本轮发送的原始消息内容。"),
|
||||
requiredInput("knowledgeItems", "知识条目", VariableTypeObjectArray, "上游知识检索节点命中的知识条目列表。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
enumOutput("answerability", "可回答性", "Answerability decision.", []VariableValueOption{
|
||||
enumOutput("answerability", "可回答性", "知识库结果是否足够支撑回答的判断。", []VariableValueOption{
|
||||
valueOption("answerable", "可以回答", "检索结果足够支撑回答。"),
|
||||
valueOption("unanswerable", "无法回答", "检索结果不足,应该走兜底或追问。"),
|
||||
}),
|
||||
output("reason", VariableTypeString, "Decision reason."),
|
||||
output("reason", "判断原因", VariableTypeString, "可回答性判断的原因说明。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -156,11 +156,11 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "BotIcon",
|
||||
RiskLevel: NodeRiskLevelMedium,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("userMessage", VariableTypeString, "Current user message content."),
|
||||
optionalInput("knowledgeItems", VariableTypeObjectArray, "Retrieved knowledge items."),
|
||||
requiredInput("userMessage", "用户消息", VariableTypeString, "客户本轮发送的原始消息内容。"),
|
||||
optionalInput("knowledgeItems", "知识条目", VariableTypeObjectArray, "可用于生成回复的知识库检索结果。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("replyText", VariableTypeString, "Generated reply text."),
|
||||
output("replyText", "回复内容", VariableTypeString, "大模型生成的客户可见回复文本。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -170,7 +170,7 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "GitBranchIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
OutputSchema: []VariableSpec{
|
||||
output("matched", VariableTypeBoolean, "Whether the condition matched."),
|
||||
output("matched", "是否命中", VariableTypeBoolean, "条件节点是否命中了某个条件分支。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -180,13 +180,13 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "SearchIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("userMessage", VariableTypeString, "Current user message content."),
|
||||
requiredInput("userMessage", "用户消息", VariableTypeString, "客户本轮发送的原始消息内容。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("intent", VariableTypeString, "Detected user intent."),
|
||||
output("riskLevel", VariableTypeString, "Detected risk level."),
|
||||
output("needTicket", VariableTypeBoolean, "Whether a ticket is recommended."),
|
||||
output("needHumanHandoff", VariableTypeBoolean, "Whether human handoff is recommended."),
|
||||
output("intent", "用户意图", VariableTypeString, "从会话中识别出的客户意图。"),
|
||||
output("riskLevel", "风险等级", VariableTypeString, "本轮会话的风险等级判断。"),
|
||||
output("needTicket", "需要工单", VariableTypeBoolean, "是否建议进入工单处理流程。"),
|
||||
output("needHumanHandoff", "需要转人工", VariableTypeBoolean, "是否建议转人工客服处理。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -196,10 +196,10 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "ClipboardListIcon",
|
||||
RiskLevel: NodeRiskLevelMedium,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("issue", VariableTypeString, "Issue summary."),
|
||||
requiredInput("issue", "问题摘要", VariableTypeString, "需要整理进工单的客户问题摘要。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("ticketDraft", VariableTypeObject, "Draft ticket payload."),
|
||||
output("ticketDraft", "工单草稿", VariableTypeObject, "根据会话内容整理出的待确认工单草稿。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -210,11 +210,11 @@ func DefaultRegistry() *Registry {
|
||||
RiskLevel: NodeRiskLevelMedium,
|
||||
Interruptible: true,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("prompt", VariableTypeString, "Confirmation prompt."),
|
||||
requiredInput("prompt", "确认提示", VariableTypeString, "发送给客户用于确认操作的提示文本。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("confirmed", VariableTypeBoolean, "Whether the user confirmed."),
|
||||
output("responseText", VariableTypeString, "Confirmation response text."),
|
||||
output("confirmed", "已确认", VariableTypeBoolean, "客户是否明确确认继续执行。"),
|
||||
output("responseText", "确认回复", VariableTypeString, "客户针对确认提示给出的回复文本。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -225,14 +225,14 @@ func DefaultRegistry() *Registry {
|
||||
RiskLevel: NodeRiskLevelHigh,
|
||||
RequiresConfirmationPredecessor: true,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("ticketDraft", VariableTypeObject, "Confirmed draft ticket payload."),
|
||||
requiredInput("confirmed", VariableTypeBoolean, "Confirmation result."),
|
||||
requiredInput("ticketDraft", "工单草稿", VariableTypeObject, "已经由客户确认的工单草稿内容。"),
|
||||
requiredInput("confirmed", "已确认", VariableTypeBoolean, "客户是否已确认创建工单。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("ticketId", VariableTypeInteger, "Created ticket ID."),
|
||||
output("ticketNo", VariableTypeString, "Created ticket number."),
|
||||
output("created", VariableTypeBoolean, "Whether the ticket was created."),
|
||||
output("message", VariableTypeString, "Customer-visible ticket creation result."),
|
||||
output("ticketId", "工单 ID", VariableTypeInteger, "创建成功后的工单内部编号。"),
|
||||
output("ticketNo", "工单编号", VariableTypeString, "创建成功后的客户可见工单编号。"),
|
||||
output("created", "已创建", VariableTypeBoolean, "工单是否已经成功创建。"),
|
||||
output("message", "结果消息", VariableTypeString, "发送给客户的工单创建结果说明。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -242,22 +242,22 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "HeadphonesIcon",
|
||||
RiskLevel: NodeRiskLevelHigh,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("reason", VariableTypeString, "Handoff reason."),
|
||||
optionalInput("confirmed", VariableTypeBoolean, "Confirmation result."),
|
||||
requiredInput("reason", "转人工原因", VariableTypeString, "触发转人工处理的业务原因。"),
|
||||
optionalInput("confirmed", "已确认", VariableTypeBoolean, "客户是否已确认转人工。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("handoffId", VariableTypeInteger, "Handoff operation ID."),
|
||||
output("reason", VariableTypeString, "Handoff reason."),
|
||||
enumOutput("decision", "转人工结果", "Handoff dispatch decision.", []VariableValueOption{
|
||||
output("handoffId", "转人工记录 ID", VariableTypeInteger, "本次转人工操作的内部记录编号。"),
|
||||
output("reason", "转人工原因", VariableTypeString, "本次转人工处理的原因说明。"),
|
||||
enumOutput("decision", "转人工结果", "转人工分配或排队结果。", []VariableValueOption{
|
||||
valueOption("assigned", "已分配客服", "已成功分配给人工客服。"),
|
||||
valueOption("team_pool", "团队队列等待", "暂未分配到客服,进入团队等待队列。"),
|
||||
valueOption("global_pool", "全局队列等待", "非服务时间或无可用团队,进入全局等待队列。"),
|
||||
valueOption("off_hours", "非服务时间", "当前不在人工客服服务时间内。"),
|
||||
valueOption("cancelled", "已取消转人工", "由于未确认或条件不满足,未执行转人工。"),
|
||||
}),
|
||||
output("teamId", VariableTypeInteger, "Assigned or pending team ID."),
|
||||
output("assigneeId", VariableTypeInteger, "Assigned agent user ID."),
|
||||
output("message", VariableTypeString, "Customer-visible handoff notice."),
|
||||
output("teamId", "客服组 ID", VariableTypeInteger, "已分配或等待中的客服组编号。"),
|
||||
output("assigneeId", "客服 ID", VariableTypeInteger, "已分配的人工客服用户编号。"),
|
||||
output("message", "转人工提示", VariableTypeString, "发送给客户的转人工结果提示。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -267,11 +267,11 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "SendIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
InputSchema: []VariableSpec{
|
||||
requiredInput("replyText", VariableTypeString, "Customer-visible reply text."),
|
||||
requiredInput("replyText", "回复内容", VariableTypeString, "将发送或返回给客户的最终回复文本。"),
|
||||
},
|
||||
OutputSchema: []VariableSpec{
|
||||
output("sent", VariableTypeBoolean, "Whether the reply was sent."),
|
||||
output("replyMessageId", VariableTypeInteger, "Reply message ID."),
|
||||
output("sent", "已发送", VariableTypeBoolean, "回复是否已经成功发送或返回。"),
|
||||
output("replyMessageId", "回复消息 ID", VariableTypeInteger, "发送成功后的回复消息编号。"),
|
||||
},
|
||||
},
|
||||
NodeSpec{
|
||||
@@ -281,22 +281,22 @@ func DefaultRegistry() *Registry {
|
||||
Icon: "FlagIcon",
|
||||
RiskLevel: NodeRiskLevelLow,
|
||||
OutputSchema: []VariableSpec{
|
||||
output("status", VariableTypeString, "Workflow terminal status."),
|
||||
output("status", "结束状态", VariableTypeString, "工作流执行结束时的状态。"),
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func requiredInput(name string, variableType VariableType, description string) VariableSpec {
|
||||
return VariableSpec{Name: name, Type: variableType, Required: true, Description: description}
|
||||
func requiredInput(name string, label string, variableType VariableType, description string) VariableSpec {
|
||||
return VariableSpec{Name: name, Label: label, Type: variableType, Required: true, Description: description}
|
||||
}
|
||||
|
||||
func optionalInput(name string, variableType VariableType, description string) VariableSpec {
|
||||
return VariableSpec{Name: name, Type: variableType, Description: description}
|
||||
func optionalInput(name string, label string, variableType VariableType, description string) VariableSpec {
|
||||
return VariableSpec{Name: name, Label: label, Type: variableType, Description: description}
|
||||
}
|
||||
|
||||
func output(name string, variableType VariableType, description string) VariableSpec {
|
||||
return VariableSpec{Name: name, Type: variableType, Description: description}
|
||||
func output(name string, label string, variableType VariableType, description string) VariableSpec {
|
||||
return VariableSpec{Name: name, Label: label, Type: variableType, Description: description}
|
||||
}
|
||||
|
||||
func enumOutput(name string, label string, description string, options []VariableValueOption) VariableSpec {
|
||||
|
||||
@@ -2,6 +2,19 @@ package registry
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDefaultRegistryVariablesHaveBusinessLabels(t *testing.T) {
|
||||
for _, spec := range DefaultRegistry().List() {
|
||||
for _, variable := range append(spec.InputSchema, spec.OutputSchema...) {
|
||||
if variable.Label == "" {
|
||||
t.Fatalf("%s.%s is missing business label", spec.Type, variable.Name)
|
||||
}
|
||||
if variable.Description == "" || variable.Description == variable.Name {
|
||||
t.Fatalf("%s.%s is missing readable description", spec.Type, variable.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultRegistryExposesStartOutputs(t *testing.T) {
|
||||
spec, ok := DefaultRegistry().Get(NodeTypeStart)
|
||||
if !ok {
|
||||
|
||||
Reference in New Issue
Block a user