refactor: change pointer receivers to value types for Conversation and UserMessage in various structs and functions
This commit is contained in:
@@ -18,9 +18,6 @@ type prepareService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *prepareService) selectSkill(ctx context.Context, req Request) (*models.SkillDefinition, string, string, error) {
|
func (s *prepareService) selectSkill(ctx context.Context, req Request) (*models.SkillDefinition, string, string, error) {
|
||||||
if req.UserMessage == nil || req.Conversation == nil {
|
|
||||||
return nil, "", "", nil
|
|
||||||
}
|
|
||||||
result, err := skills.Select(ctx, skills.RuntimeContext{
|
result, err := skills.Select(ctx, skills.RuntimeContext{
|
||||||
AIAgent: req.AIAgent,
|
AIAgent: req.AIAgent,
|
||||||
AIConfig: req.AIConfig,
|
AIConfig: req.AIConfig,
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
Conversation *models.Conversation
|
Conversation models.Conversation
|
||||||
UserMessage *models.Message
|
UserMessage models.Message
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
AIConfig models.AIConfig
|
AIConfig models.AIConfig
|
||||||
ManualSkillCode string
|
ManualSkillCode string
|
||||||
@@ -19,7 +19,7 @@ type Request struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResumeRequest struct {
|
type ResumeRequest struct {
|
||||||
Conversation *models.Conversation
|
Conversation models.Conversation
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
AIConfig models.AIConfig
|
AIConfig models.AIConfig
|
||||||
CheckPointID string
|
CheckPointID string
|
||||||
|
|||||||
@@ -28,21 +28,22 @@ func DebugRunSkill(ctx context.Context, req request.SkillDebugRunRequest) (*resp
|
|||||||
if aiConfig == nil {
|
if aiConfig == nil {
|
||||||
return nil, errorsx.InvalidParam("AI Agent关联的AI配置不存在")
|
return nil, errorsx.InvalidParam("AI Agent关联的AI配置不存在")
|
||||||
}
|
}
|
||||||
conversation := &models.Conversation{ID: req.ConversationID, AIAgentID: req.AIAgentID}
|
var conversation *models.Conversation
|
||||||
if req.ConversationID > 0 {
|
if req.ConversationID > 0 {
|
||||||
conversation = svc.ConversationService.Get(req.ConversationID)
|
if conversation = svc.ConversationService.Get(req.ConversationID); conversation == nil {
|
||||||
if conversation == nil {
|
|
||||||
return nil, errorsx.InvalidParam("会话不存在")
|
return nil, errorsx.InvalidParam("会话不存在")
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
conversation = &models.Conversation{ID: req.ConversationID, AIAgentID: req.AIAgentID}
|
||||||
}
|
}
|
||||||
message := &models.Message{
|
message := models.Message{
|
||||||
ConversationID: req.ConversationID,
|
ConversationID: req.ConversationID,
|
||||||
SenderType: enums.IMSenderTypeCustomer,
|
SenderType: enums.IMSenderTypeCustomer,
|
||||||
MessageType: enums.IMMessageTypeText,
|
MessageType: enums.IMMessageTypeText,
|
||||||
Content: strings.TrimSpace(req.UserMessage),
|
Content: strings.TrimSpace(req.UserMessage),
|
||||||
}
|
}
|
||||||
summary, err := Service.Run(ctx, applicationruntime.Request{
|
summary, err := Service.Run(ctx, applicationruntime.Request{
|
||||||
Conversation: conversation,
|
Conversation: *conversation,
|
||||||
UserMessage: message,
|
UserMessage: message,
|
||||||
AIAgent: *aiAgent,
|
AIAgent: *aiAgent,
|
||||||
AIConfig: *aiConfig,
|
AIConfig: *aiConfig,
|
||||||
@@ -90,7 +91,7 @@ func DebugResumeSkill(ctx context.Context, req request.SkillDebugResumeRequest)
|
|||||||
}
|
}
|
||||||
resumeText := strings.TrimSpace(req.UserMessage)
|
resumeText := strings.TrimSpace(req.UserMessage)
|
||||||
summary, err := Service.Resume(ctx, applicationruntime.ResumeRequest{
|
summary, err := Service.Resume(ctx, applicationruntime.ResumeRequest{
|
||||||
Conversation: conversation,
|
Conversation: *conversation,
|
||||||
AIAgent: *aiAgent,
|
AIAgent: *aiAgent,
|
||||||
AIConfig: *aiConfig,
|
AIConfig: *aiConfig,
|
||||||
CheckPointID: strings.TrimSpace(req.CheckPointID),
|
CheckPointID: strings.TrimSpace(req.CheckPointID),
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func buildRunMessages(ctx context.Context, req RunInput, summary *RunResult, collector *callbacks.RuntimeTraceCollector) []*schema.Message {
|
func buildRunMessages(ctx context.Context, req RunInput, summary *RunResult, collector *callbacks.RuntimeTraceCollector) []*schema.Message {
|
||||||
if req.Conversation == nil || req.UserMessage == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
history := adapter.BuildHistoryMessages(req.Conversation.ID, req.UserMessage.ID, 12)
|
history := adapter.BuildHistoryMessages(req.Conversation.ID, req.UserMessage.ID, 12)
|
||||||
if summary != nil {
|
if summary != nil {
|
||||||
summary.HistoryMessageCount = len(history.Messages)
|
summary.HistoryMessageCount = len(history.Messages)
|
||||||
@@ -39,7 +36,7 @@ func buildRunMessages(ctx context.Context, req RunInput, summary *RunResult, col
|
|||||||
}
|
}
|
||||||
|
|
||||||
func appendRetrievedContext(ctx context.Context, req RunInput, summary *RunResult, collector *callbacks.RuntimeTraceCollector, messages *[]*schema.Message) knowledgeGuardDecision {
|
func appendRetrievedContext(ctx context.Context, req RunInput, summary *RunResult, collector *callbacks.RuntimeTraceCollector, messages *[]*schema.Message) knowledgeGuardDecision {
|
||||||
if req.UserMessage == nil || messages == nil {
|
if messages == nil {
|
||||||
return knowledgeGuardDecision{}
|
return knowledgeGuardDecision{}
|
||||||
}
|
}
|
||||||
retriever := retrievers.NewKnowledgeRetriever(req.AIAgent)
|
retriever := retrievers.NewKnowledgeRetriever(req.AIAgent)
|
||||||
|
|||||||
@@ -33,16 +33,6 @@ func (s *Service) ExecuteRun(ctx context.Context, req RunInput) (*RunResult, err
|
|||||||
}
|
}
|
||||||
collector := callbacks.NewRuntimeTraceCollector()
|
collector := callbacks.NewRuntimeTraceCollector()
|
||||||
collector.Data.RunID = summary.RunID
|
collector.Data.RunID = summary.RunID
|
||||||
if req.Conversation == nil || req.UserMessage == nil {
|
|
||||||
summary.Status = "error"
|
|
||||||
summary.ErrorMessage = "invalid runtime request"
|
|
||||||
collector.Data.Status = summary.Status
|
|
||||||
collector.Data.Error.Message = summary.ErrorMessage
|
|
||||||
collector.Data.Error.Stage = "prepare"
|
|
||||||
summary.TraceData = collector.Marshal()
|
|
||||||
return summary, fmt.Errorf("%s", summary.ErrorMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
toolDefs, err := factory.NewToolFactory().BuildMCPTools(req.AIAgent)
|
toolDefs, err := factory.NewToolFactory().BuildMCPTools(req.AIAgent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
summary.Status = "error"
|
summary.Status = "error"
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type RunInput struct {
|
type RunInput struct {
|
||||||
Conversation *models.Conversation
|
Conversation models.Conversation
|
||||||
UserMessage *models.Message
|
UserMessage models.Message
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
AIConfig models.AIConfig
|
AIConfig models.AIConfig
|
||||||
SelectedSkill *models.SkillDefinition
|
SelectedSkill *models.SkillDefinition
|
||||||
@@ -18,7 +18,7 @@ type RunInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResumeInput struct {
|
type ResumeInput struct {
|
||||||
Conversation *models.Conversation
|
Conversation models.Conversation
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
AIConfig models.AIConfig
|
AIConfig models.AIConfig
|
||||||
CheckPointID string
|
CheckPointID string
|
||||||
|
|||||||
@@ -30,17 +30,14 @@ type AnalyzeConversationResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AnalyzeConversationGraph struct {
|
type AnalyzeConversationGraph struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAnalyzeConversationGraph(conversation *models.Conversation) *AnalyzeConversationGraph {
|
func NewAnalyzeConversationGraph(conversation models.Conversation) *AnalyzeConversationGraph {
|
||||||
return &AnalyzeConversationGraph{conversation: conversation}
|
return &AnalyzeConversationGraph{conversation: conversation}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *AnalyzeConversationGraph) Run(_ context.Context, argumentsInJSON string) (string, error) {
|
func (g *AnalyzeConversationGraph) Run(_ context.Context, argumentsInJSON string) (string, error) {
|
||||||
if g == nil || g.conversation == nil {
|
|
||||||
return "", fmt.Errorf("analyze conversation graph not initialized")
|
|
||||||
}
|
|
||||||
input, err := g.parseInput(argumentsInJSON)
|
input, err := g.parseInput(argumentsInJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -68,7 +65,7 @@ func (g *AnalyzeConversationGraph) parseInput(argumentsInJSON string) (AnalyzeCo
|
|||||||
return input, nil
|
return input, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildAnalyzeConversationResult(conversation *models.Conversation, messages []models.Message, input AnalyzeConversationInput) AnalyzeConversationResult {
|
func buildAnalyzeConversationResult(conversation models.Conversation, messages []models.Message, input AnalyzeConversationInput) AnalyzeConversationResult {
|
||||||
joined := strings.ToLower(buildConversationCorpus(conversation, messages, input))
|
joined := strings.ToLower(buildConversationCorpus(conversation, messages, input))
|
||||||
signals := collectRiskSignals(joined, input)
|
signals := collectRiskSignals(joined, input)
|
||||||
intent := detectUserIntent(joined, input)
|
intent := detectUserIntent(joined, input)
|
||||||
@@ -85,14 +82,14 @@ func buildAnalyzeConversationResult(conversation *models.Conversation, messages
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConversationSummary(conversation *models.Conversation, messages []models.Message, input AnalyzeConversationInput) string {
|
func buildConversationSummary(conversation models.Conversation, messages []models.Message, input AnalyzeConversationInput) string {
|
||||||
parts := make([]string, 0, 4)
|
parts := make([]string, 0, 4)
|
||||||
if conversation != nil && strings.TrimSpace(conversation.Subject) != "" {
|
if strings.TrimSpace(conversation.Subject) != "" {
|
||||||
parts = append(parts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
parts = append(parts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
||||||
}
|
}
|
||||||
if input.ObservedIssue != "" {
|
if input.ObservedIssue != "" {
|
||||||
parts = append(parts, "当前问题:"+input.ObservedIssue)
|
parts = append(parts, "当前问题:"+input.ObservedIssue)
|
||||||
} else if conversation != nil && strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
} else if strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
||||||
parts = append(parts, "当前问题:"+strings.TrimSpace(conversation.LastMessageSummary))
|
parts = append(parts, "当前问题:"+strings.TrimSpace(conversation.LastMessageSummary))
|
||||||
}
|
}
|
||||||
if digest := buildRecentMessageDigest(messages); digest != "" {
|
if digest := buildRecentMessageDigest(messages); digest != "" {
|
||||||
@@ -104,12 +101,10 @@ func buildConversationSummary(conversation *models.Conversation, messages []mode
|
|||||||
return strings.TrimSpace(strings.Join(parts, "\n"))
|
return strings.TrimSpace(strings.Join(parts, "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConversationCorpus(conversation *models.Conversation, messages []models.Message, input AnalyzeConversationInput) string {
|
func buildConversationCorpus(conversation models.Conversation, messages []models.Message, input AnalyzeConversationInput) string {
|
||||||
parts := make([]string, 0, len(messages)+4)
|
parts := make([]string, 0, len(messages)+4)
|
||||||
if conversation != nil {
|
|
||||||
parts = append(parts, strings.TrimSpace(conversation.Subject))
|
parts = append(parts, strings.TrimSpace(conversation.Subject))
|
||||||
parts = append(parts, strings.TrimSpace(conversation.LastMessageSummary))
|
parts = append(parts, strings.TrimSpace(conversation.LastMessageSummary))
|
||||||
}
|
|
||||||
parts = append(parts, input.Goal, input.ObservedIssue, input.AdditionalContext)
|
parts = append(parts, input.Goal, input.ObservedIssue, input.AdditionalContext)
|
||||||
for i := range messages {
|
for i := range messages {
|
||||||
parts = append(parts, strings.TrimSpace(messages[i].Content))
|
parts = append(parts, strings.TrimSpace(messages[i].Content))
|
||||||
@@ -203,12 +198,12 @@ func recommendQuestions(intent string, signals []string, input AnalyzeConversati
|
|||||||
return questions
|
return questions
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConversationAnalysisFacts(conversation *models.Conversation, messages []models.Message) []string {
|
func buildConversationAnalysisFacts(conversation models.Conversation, messages []models.Message) []string {
|
||||||
facts := make([]string, 0, 4)
|
facts := make([]string, 0, 4)
|
||||||
if conversation != nil && strings.TrimSpace(conversation.Subject) != "" {
|
if strings.TrimSpace(conversation.Subject) != "" {
|
||||||
facts = append(facts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
facts = append(facts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
||||||
}
|
}
|
||||||
if conversation != nil && strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
if strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
||||||
facts = append(facts, "最近摘要:"+strings.TrimSpace(conversation.LastMessageSummary))
|
facts = append(facts, "最近摘要:"+strings.TrimSpace(conversation.LastMessageSummary))
|
||||||
}
|
}
|
||||||
if digest := buildRecentMessageDigest(messages); digest != "" {
|
if digest := buildRecentMessageDigest(messages); digest != "" {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestBuildAnalyzeConversationResult_RecommendsHandoffForComplaint(t *testing.T) {
|
func TestBuildAnalyzeConversationResult_RecommendsHandoffForComplaint(t *testing.T) {
|
||||||
conversation := &models.Conversation{
|
conversation := models.Conversation{
|
||||||
Subject: "用户投诉扣费异常",
|
Subject: "用户投诉扣费异常",
|
||||||
LastMessageSummary: "用户反馈被重复扣费,并要求人工处理",
|
LastMessageSummary: "用户反馈被重复扣费,并要求人工处理",
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ func TestBuildAnalyzeConversationResult_RecommendsHandoffForComplaint(t *testing
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildAnalyzeConversationResult_RecommendsPrepareTicket(t *testing.T) {
|
func TestBuildAnalyzeConversationResult_RecommendsPrepareTicket(t *testing.T) {
|
||||||
conversation := &models.Conversation{
|
conversation := models.Conversation{
|
||||||
Subject: "订单无法支付",
|
Subject: "订单无法支付",
|
||||||
LastMessageSummary: "用户要求登记问题并尽快处理",
|
LastMessageSummary: "用户要求登记问题并尽快处理",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreateTicketGraph struct {
|
type CreateTicketGraph struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
aiAgent models.AIAgent
|
aiAgent models.AIAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCreateTicketGraph(conversation *models.Conversation, aiAgent models.AIAgent) *CreateTicketGraph {
|
func NewCreateTicketGraph(conversation models.Conversation, aiAgent models.AIAgent) *CreateTicketGraph {
|
||||||
return &CreateTicketGraph{
|
return &CreateTicketGraph{
|
||||||
conversation: conversation,
|
conversation: conversation,
|
||||||
aiAgent: aiAgent,
|
aiAgent: aiAgent,
|
||||||
@@ -49,9 +49,6 @@ func NewCreateTicketGraph(conversation *models.Conversation, aiAgent models.AIAg
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *CreateTicketGraph) Run(ctx context.Context, argumentsInJSON string) (string, error) {
|
func (g *CreateTicketGraph) Run(ctx context.Context, argumentsInJSON string) (string, error) {
|
||||||
if g == nil || g.conversation == nil {
|
|
||||||
return "", fmt.Errorf("create ticket graph not initialized")
|
|
||||||
}
|
|
||||||
wasInterrupted, hasState, state := componenttool.GetInterruptState[CreateTicketGraphState](ctx)
|
wasInterrupted, hasState, state := componenttool.GetInterruptState[CreateTicketGraphState](ctx)
|
||||||
if !wasInterrupted {
|
if !wasInterrupted {
|
||||||
req, err := g.buildCreateRequest(argumentsInJSON)
|
req, err := g.buildCreateRequest(argumentsInJSON)
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HandoffGraph struct {
|
type HandoffGraph struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
aiAgent models.AIAgent
|
aiAgent models.AIAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandoffGraph(conversation *models.Conversation, aiAgent models.AIAgent) *HandoffGraph {
|
func NewHandoffGraph(conversation models.Conversation, aiAgent models.AIAgent) *HandoffGraph {
|
||||||
return &HandoffGraph{
|
return &HandoffGraph{
|
||||||
conversation: conversation,
|
conversation: conversation,
|
||||||
aiAgent: aiAgent,
|
aiAgent: aiAgent,
|
||||||
@@ -44,9 +44,6 @@ func NewHandoffGraph(conversation *models.Conversation, aiAgent models.AIAgent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *HandoffGraph) Run(ctx context.Context, argumentsInJSON string) (string, error) {
|
func (g *HandoffGraph) Run(ctx context.Context, argumentsInJSON string) (string, error) {
|
||||||
if g == nil || g.conversation == nil {
|
|
||||||
return "", fmt.Errorf("handoff graph not initialized")
|
|
||||||
}
|
|
||||||
wasInterrupted, hasState, state := componenttool.GetInterruptState[HandoffGraphState](ctx)
|
wasInterrupted, hasState, state := componenttool.GetInterruptState[HandoffGraphState](ctx)
|
||||||
if !wasInterrupted {
|
if !wasInterrupted {
|
||||||
reason, err := g.buildReason(argumentsInJSON)
|
reason, err := g.buildReason(argumentsInJSON)
|
||||||
|
|||||||
@@ -34,17 +34,14 @@ type PrepareTicketDraftResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PrepareTicketDraftGraph struct {
|
type PrepareTicketDraftGraph struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPrepareTicketDraftGraph(conversation *models.Conversation) *PrepareTicketDraftGraph {
|
func NewPrepareTicketDraftGraph(conversation models.Conversation) *PrepareTicketDraftGraph {
|
||||||
return &PrepareTicketDraftGraph{conversation: conversation}
|
return &PrepareTicketDraftGraph{conversation: conversation}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *PrepareTicketDraftGraph) Run(_ context.Context, argumentsInJSON string) (string, error) {
|
func (g *PrepareTicketDraftGraph) Run(_ context.Context, argumentsInJSON string) (string, error) {
|
||||||
if g == nil || g.conversation == nil {
|
|
||||||
return "", fmt.Errorf("prepare ticket draft graph not initialized")
|
|
||||||
}
|
|
||||||
input, err := g.parseInput(argumentsInJSON)
|
input, err := g.parseInput(argumentsInJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -75,7 +72,7 @@ func (g *PrepareTicketDraftGraph) parseInput(argumentsInJSON string) (PrepareTic
|
|||||||
return input, nil
|
return input, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPrepareTicketDraftResult(conversation *models.Conversation, messages []models.Message, input PrepareTicketDraftInput) PrepareTicketDraftResult {
|
func buildPrepareTicketDraftResult(conversation models.Conversation, messages []models.Message, input PrepareTicketDraftInput) PrepareTicketDraftResult {
|
||||||
result := PrepareTicketDraftResult{
|
result := PrepareTicketDraftResult{
|
||||||
Priority: input.Priority,
|
Priority: input.Priority,
|
||||||
Severity: input.Severity,
|
Severity: input.Severity,
|
||||||
@@ -97,22 +94,22 @@ func buildPrepareTicketDraftResult(conversation *models.Conversation, messages [
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildDraftTitle(conversation *models.Conversation, input PrepareTicketDraftInput) string {
|
func buildDraftTitle(conversation models.Conversation, input PrepareTicketDraftInput) string {
|
||||||
switch {
|
switch {
|
||||||
case input.Title != "":
|
case input.Title != "":
|
||||||
return limitText(input.Title, 80)
|
return limitText(input.Title, 80)
|
||||||
case input.Issue != "":
|
case input.Issue != "":
|
||||||
return limitText(input.Issue, 80)
|
return limitText(input.Issue, 80)
|
||||||
case conversation != nil && strings.TrimSpace(conversation.Subject) != "":
|
case strings.TrimSpace(conversation.Subject) != "":
|
||||||
return limitText(conversation.Subject, 80)
|
return limitText(conversation.Subject, 80)
|
||||||
case conversation != nil:
|
case strings.TrimSpace(conversation.LastMessageSummary) != "":
|
||||||
return limitText(conversation.LastMessageSummary, 80)
|
return limitText(conversation.LastMessageSummary, 80)
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildDraftDescription(conversation *models.Conversation, messages []models.Message, input PrepareTicketDraftInput) string {
|
func buildDraftDescription(conversation models.Conversation, messages []models.Message, input PrepareTicketDraftInput) string {
|
||||||
if input.Description != "" {
|
if input.Description != "" {
|
||||||
return input.Description
|
return input.Description
|
||||||
}
|
}
|
||||||
@@ -129,7 +126,7 @@ func buildDraftDescription(conversation *models.Conversation, messages []models.
|
|||||||
if input.CurrentAttempt != "" {
|
if input.CurrentAttempt != "" {
|
||||||
parts = append(parts, "已尝试处理:"+input.CurrentAttempt)
|
parts = append(parts, "已尝试处理:"+input.CurrentAttempt)
|
||||||
}
|
}
|
||||||
if conversation != nil && strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
if strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
||||||
parts = append(parts, "会话摘要:"+strings.TrimSpace(conversation.LastMessageSummary))
|
parts = append(parts, "会话摘要:"+strings.TrimSpace(conversation.LastMessageSummary))
|
||||||
}
|
}
|
||||||
if recent := buildRecentMessageDigest(messages); recent != "" {
|
if recent := buildRecentMessageDigest(messages); recent != "" {
|
||||||
@@ -145,12 +142,12 @@ func hasSufficientIssueContext(input PrepareTicketDraftInput, description string
|
|||||||
return len([]rune(strings.TrimSpace(description))) >= 30
|
return len([]rune(strings.TrimSpace(description))) >= 30
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConversationFacts(conversation *models.Conversation, messages []models.Message) []string {
|
func buildConversationFacts(conversation models.Conversation, messages []models.Message) []string {
|
||||||
facts := make([]string, 0, 4)
|
facts := make([]string, 0, 4)
|
||||||
if conversation != nil && strings.TrimSpace(conversation.Subject) != "" {
|
if strings.TrimSpace(conversation.Subject) != "" {
|
||||||
facts = append(facts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
facts = append(facts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
||||||
}
|
}
|
||||||
if conversation != nil && strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
if strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
||||||
facts = append(facts, "最近摘要:"+strings.TrimSpace(conversation.LastMessageSummary))
|
facts = append(facts, "最近摘要:"+strings.TrimSpace(conversation.LastMessageSummary))
|
||||||
}
|
}
|
||||||
if digest := buildRecentMessageDigest(messages); digest != "" {
|
if digest := buildRecentMessageDigest(messages); digest != "" {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestBuildPrepareTicketDraftResult_UsesConversationFallbacks(t *testing.T) {
|
func TestBuildPrepareTicketDraftResult_UsesConversationFallbacks(t *testing.T) {
|
||||||
conversation := &models.Conversation{
|
conversation := models.Conversation{
|
||||||
Subject: "企业微信登录异常",
|
Subject: "企业微信登录异常",
|
||||||
LastMessageSummary: "用户反馈企业微信扫码后页面空白,无法进入工作台",
|
LastMessageSummary: "用户反馈企业微信扫码后页面空白,无法进入工作台",
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ func TestBuildPrepareTicketDraftResult_UsesConversationFallbacks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildPrepareTicketDraftResult_ReadyWithExplicitIssue(t *testing.T) {
|
func TestBuildPrepareTicketDraftResult_ReadyWithExplicitIssue(t *testing.T) {
|
||||||
conversation := &models.Conversation{
|
conversation := models.Conversation{
|
||||||
Subject: "订单支付失败",
|
Subject: "订单支付失败",
|
||||||
LastMessageSummary: "用户反馈连续支付失败",
|
LastMessageSummary: "用户反馈连续支付失败",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,17 +26,14 @@ type TriageServiceRequestResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TriageServiceRequestGraph struct {
|
type TriageServiceRequestGraph struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTriageServiceRequestGraph(conversation *models.Conversation) *TriageServiceRequestGraph {
|
func NewTriageServiceRequestGraph(conversation models.Conversation) *TriageServiceRequestGraph {
|
||||||
return &TriageServiceRequestGraph{conversation: conversation}
|
return &TriageServiceRequestGraph{conversation: conversation}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *TriageServiceRequestGraph) Run(_ context.Context, argumentsInJSON string) (string, error) {
|
func (g *TriageServiceRequestGraph) Run(_ context.Context, argumentsInJSON string) (string, error) {
|
||||||
if g == nil || g.conversation == nil {
|
|
||||||
return "", fmt.Errorf("triage service request graph not initialized")
|
|
||||||
}
|
|
||||||
input, err := g.parseInput(argumentsInJSON)
|
input, err := g.parseInput(argumentsInJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestTriageServiceRequestResult_PrepareTicket(t *testing.T) {
|
func TestTriageServiceRequestResult_PrepareTicket(t *testing.T) {
|
||||||
conversation := &models.Conversation{
|
conversation := models.Conversation{
|
||||||
Subject: "支付失败需要登记工单",
|
Subject: "支付失败需要登记工单",
|
||||||
LastMessageSummary: "用户要求建单跟进支付失败问题",
|
LastMessageSummary: "用户要求建单跟进支付失败问题",
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ func TestTriageServiceRequestResult_PrepareTicket(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTriageServiceRequestResult_Handoff(t *testing.T) {
|
func TestTriageServiceRequestResult_Handoff(t *testing.T) {
|
||||||
conversation := &models.Conversation{
|
conversation := models.Conversation{
|
||||||
Subject: "投诉转人工",
|
Subject: "投诉转人工",
|
||||||
LastMessageSummary: "用户要求人工处理扣费投诉",
|
LastMessageSummary: "用户要求人工处理扣费投诉",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func TestResolveBuildsStaticToolMetadata(t *testing.T) {
|
|||||||
code: toolx.GraphCreateTicketConfirm.Code,
|
code: toolx.GraphCreateTicketConfirm.Code,
|
||||||
})
|
})
|
||||||
toolSet, err := r.Resolve(registry.Context{
|
toolSet, err := r.Resolve(registry.Context{
|
||||||
Conversation: &models.Conversation{ID: 1},
|
Conversation: models.Conversation{ID: 1},
|
||||||
AIAgent: models.AIAgent{ID: 1},
|
AIAgent: models.AIAgent{ID: 1},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
Conversation *models.Conversation
|
Conversation models.Conversation
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
AIConfig models.AIConfig
|
AIConfig models.AIConfig
|
||||||
UserMessage *models.Message
|
UserMessage models.Message
|
||||||
AllowedToolCodes []string
|
AllowedToolCodes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ func (e *runtimeReplyExecutor) Run(ctx context.Context, conversation models.Conv
|
|||||||
}
|
}
|
||||||
runtimeStartedAt := time.Now()
|
runtimeStartedAt := time.Now()
|
||||||
summary, err := Service.Run(ctx, applicationruntime.Request{
|
summary, err := Service.Run(ctx, applicationruntime.Request{
|
||||||
Conversation: &conversation,
|
Conversation: conversation,
|
||||||
UserMessage: &message,
|
UserMessage: message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: aiAgent,
|
||||||
AIConfig: *aiConfig,
|
AIConfig: *aiConfig,
|
||||||
})
|
})
|
||||||
@@ -51,7 +51,7 @@ func (e *runtimeReplyExecutor) ResumePendingInterrupt(ctx context.Context, conve
|
|||||||
trace.ResumeSource = "pending_interrupt"
|
trace.ResumeSource = "pending_interrupt"
|
||||||
}
|
}
|
||||||
summary, err := Service.Resume(ctx, applicationruntime.ResumeRequest{
|
summary, err := Service.Resume(ctx, applicationruntime.ResumeRequest{
|
||||||
Conversation: &conversation,
|
Conversation: conversation,
|
||||||
AIAgent: aiAgent,
|
AIAgent: aiAgent,
|
||||||
AIConfig: *aiConfig,
|
AIConfig: *aiConfig,
|
||||||
CheckPointID: strings.TrimSpace(pendingInterrupt.CheckPointID),
|
CheckPointID: strings.TrimSpace(pendingInterrupt.CheckPointID),
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"cs-agent/internal/ai/runtime/graphs"
|
"cs-agent/internal/ai/runtime/graphs"
|
||||||
"cs-agent/internal/ai/runtime/registry"
|
"cs-agent/internal/ai/runtime/registry"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AnalyzeConversationTool struct {
|
type AnalyzeConversationTool struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAnalyzeConversationTool() *AnalyzeConversationTool {
|
func NewAnalyzeConversationTool() *AnalyzeConversationTool {
|
||||||
@@ -36,7 +35,7 @@ func (t *AnalyzeConversationTool) Code() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *AnalyzeConversationTool) Enabled(ctx registry.Context) bool {
|
func (t *AnalyzeConversationTool) Enabled(ctx registry.Context) bool {
|
||||||
return ctx.Conversation != nil
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *AnalyzeConversationTool) Build(ctx registry.Context) (einotool.BaseTool, error) {
|
func (t *AnalyzeConversationTool) Build(ctx registry.Context) (einotool.BaseTool, error) {
|
||||||
@@ -106,8 +105,5 @@ func (t *AnalyzeConversationTool) Info(ctx context.Context) (*schema.ToolInfo, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *AnalyzeConversationTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
func (t *AnalyzeConversationTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
||||||
if t == nil || t.conversation == nil {
|
|
||||||
return "", fmt.Errorf("analyze conversation tool not initialized")
|
|
||||||
}
|
|
||||||
return graphs.NewAnalyzeConversationGraph(t.conversation).Run(ctx, argumentsInJSON)
|
return graphs.NewAnalyzeConversationGraph(t.conversation).Run(ctx, argumentsInJSON)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"cs-agent/internal/ai/runtime/graphs"
|
"cs-agent/internal/ai/runtime/graphs"
|
||||||
"cs-agent/internal/ai/runtime/registry"
|
"cs-agent/internal/ai/runtime/registry"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CreateTicketGraphTool struct {
|
type CreateTicketGraphTool struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
aiAgent models.AIAgent
|
aiAgent models.AIAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,8 +99,5 @@ func (t *CreateTicketGraphTool) Info(ctx context.Context) (*schema.ToolInfo, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *CreateTicketGraphTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
func (t *CreateTicketGraphTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
||||||
if t == nil || t.conversation == nil {
|
|
||||||
return "", fmt.Errorf("create ticket graph tool not initialized")
|
|
||||||
}
|
|
||||||
return graphs.NewCreateTicketGraph(t.conversation, t.aiAgent).Run(ctx, argumentsInJSON)
|
return graphs.NewCreateTicketGraph(t.conversation, t.aiAgent).Run(ctx, argumentsInJSON)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"cs-agent/internal/ai/runtime/graphs"
|
"cs-agent/internal/ai/runtime/graphs"
|
||||||
"cs-agent/internal/ai/runtime/registry"
|
"cs-agent/internal/ai/runtime/registry"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type HandoffGraphTool struct {
|
type HandoffGraphTool struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
aiAgent models.AIAgent
|
aiAgent models.AIAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,8 +74,5 @@ func (t *HandoffGraphTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *HandoffGraphTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
func (t *HandoffGraphTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
||||||
if t == nil || t.conversation == nil {
|
|
||||||
return "", fmt.Errorf("handoff graph tool not initialized")
|
|
||||||
}
|
|
||||||
return graphs.NewHandoffGraph(t.conversation, t.aiAgent).Run(ctx, argumentsInJSON)
|
return graphs.NewHandoffGraph(t.conversation, t.aiAgent).Run(ctx, argumentsInJSON)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"cs-agent/internal/ai/runtime/graphs"
|
"cs-agent/internal/ai/runtime/graphs"
|
||||||
"cs-agent/internal/ai/runtime/registry"
|
"cs-agent/internal/ai/runtime/registry"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PrepareTicketDraftTool struct {
|
type PrepareTicketDraftTool struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPrepareTicketDraftTool() *PrepareTicketDraftTool {
|
func NewPrepareTicketDraftTool() *PrepareTicketDraftTool {
|
||||||
@@ -36,7 +35,7 @@ func (t *PrepareTicketDraftTool) Code() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *PrepareTicketDraftTool) Enabled(ctx registry.Context) bool {
|
func (t *PrepareTicketDraftTool) Enabled(ctx registry.Context) bool {
|
||||||
return ctx.Conversation != nil
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *PrepareTicketDraftTool) Build(ctx registry.Context) (einotool.BaseTool, error) {
|
func (t *PrepareTicketDraftTool) Build(ctx registry.Context) (einotool.BaseTool, error) {
|
||||||
@@ -120,8 +119,5 @@ func (t *PrepareTicketDraftTool) Info(ctx context.Context) (*schema.ToolInfo, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *PrepareTicketDraftTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
func (t *PrepareTicketDraftTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
||||||
if t == nil || t.conversation == nil {
|
|
||||||
return "", fmt.Errorf("prepare ticket draft tool not initialized")
|
|
||||||
}
|
|
||||||
return graphs.NewPrepareTicketDraftGraph(t.conversation).Run(ctx, argumentsInJSON)
|
return graphs.NewPrepareTicketDraftGraph(t.conversation).Run(ctx, argumentsInJSON)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"cs-agent/internal/ai/runtime/graphs"
|
"cs-agent/internal/ai/runtime/graphs"
|
||||||
"cs-agent/internal/ai/runtime/registry"
|
"cs-agent/internal/ai/runtime/registry"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TriageServiceRequestTool struct {
|
type TriageServiceRequestTool struct {
|
||||||
conversation *models.Conversation
|
conversation models.Conversation
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTriageServiceRequestTool() *TriageServiceRequestTool {
|
func NewTriageServiceRequestTool() *TriageServiceRequestTool {
|
||||||
@@ -36,7 +35,7 @@ func (t *TriageServiceRequestTool) Code() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TriageServiceRequestTool) Enabled(ctx registry.Context) bool {
|
func (t *TriageServiceRequestTool) Enabled(ctx registry.Context) bool {
|
||||||
return ctx.Conversation != nil
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TriageServiceRequestTool) Build(ctx registry.Context) (einotool.BaseTool, error) {
|
func (t *TriageServiceRequestTool) Build(ctx registry.Context) (einotool.BaseTool, error) {
|
||||||
@@ -99,8 +98,5 @@ func (t *TriageServiceRequestTool) Info(ctx context.Context) (*schema.ToolInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TriageServiceRequestTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
func (t *TriageServiceRequestTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...einotool.Option) (string, error) {
|
||||||
if t == nil || t.conversation == nil {
|
|
||||||
return "", fmt.Errorf("triage service request tool not initialized")
|
|
||||||
}
|
|
||||||
return graphs.NewTriageServiceRequestGraph(t.conversation).Run(ctx, argumentsInJSON)
|
return graphs.NewTriageServiceRequestGraph(t.conversation).Run(ctx, argumentsInJSON)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user