refactor(runtime): update function signatures to use value receivers for models
This commit is contained in:
@@ -54,7 +54,7 @@ func (s *index) IndexDocumentByID(ctx context.Context, documentID int64) error {
|
|||||||
return s.IndexDocument(ctx, document)
|
return s.IndexDocument(ctx, document)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *index) IndexDocument(ctx context.Context, document *models.KnowledgeDocument) error {
|
func (s *index) IndexDocument(ctx context.Context, document models.KnowledgeDocument) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := s.markDocumentIndexPending(document.ID); err != nil {
|
if err := s.markDocumentIndexPending(document.ID); err != nil {
|
||||||
slog.Error("Failed to mark knowledge document index as pending", "document_id", document.ID, "error", err)
|
slog.Error("Failed to mark knowledge document index as pending", "document_id", document.ID, "error", err)
|
||||||
@@ -302,10 +302,7 @@ func (s *index) RebuildKnowledgeBaseIndex(ctx context.Context, knowledgeBaseID i
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildFAQChunkContent(faq *models.KnowledgeFAQ) string {
|
func buildFAQChunkContent(faq models.KnowledgeFAQ) string {
|
||||||
if faq == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
parts := []string{fmt.Sprintf("问题:%s", faq.Question)}
|
parts := []string{fmt.Sprintf("问题:%s", faq.Question)}
|
||||||
var similarQuestions []string
|
var similarQuestions []string
|
||||||
if faq.SimilarQuestions != "" {
|
if faq.SimilarQuestions != "" {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/mlogclub/simple/common/strs"
|
"github.com/mlogclub/simple/common/strs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *index) buildDocumentChunkRequest(document *models.KnowledgeDocument, knowledgeBase *models.KnowledgeBase) *ragchunk.ChunkRequest {
|
func (s *index) buildDocumentChunkRequest(document models.KnowledgeDocument, knowledgeBase models.KnowledgeBase) *ragchunk.ChunkRequest {
|
||||||
return &ragchunk.ChunkRequest{
|
return &ragchunk.ChunkRequest{
|
||||||
KnowledgeBaseID: document.KnowledgeBaseID,
|
KnowledgeBaseID: document.KnowledgeBaseID,
|
||||||
DocumentID: document.ID,
|
DocumentID: document.ID,
|
||||||
@@ -33,7 +33,7 @@ func (s *index) buildDocumentChunkRequest(document *models.KnowledgeDocument, kn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *index) buildDocumentChunks(ctx context.Context, document *models.KnowledgeDocument, knowledgeBase *models.KnowledgeBase) ([]ragchunk.ChunkResult, error) {
|
func (s *index) buildDocumentChunks(ctx context.Context, document models.KnowledgeDocument, knowledgeBase models.KnowledgeBase) ([]ragchunk.ChunkResult, error) {
|
||||||
chunks, err := s.registry.Chunk(ctx, s.buildDocumentChunkRequest(document, knowledgeBase))
|
chunks, err := s.registry.Chunk(ctx, s.buildDocumentChunkRequest(document, knowledgeBase))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to chunk document: %w", err)
|
return nil, fmt.Errorf("failed to chunk document: %w", err)
|
||||||
@@ -54,7 +54,7 @@ func collectExistingVectorIDs(chunks []models.KnowledgeChunk) []string {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *index) prepareDocumentVectors(ctx context.Context, knowledgeBase *models.KnowledgeBase, document *models.KnowledgeDocument, chunks []ragchunk.ChunkResult) ([]vectordb.Vector, []models.KnowledgeChunk, int, error) {
|
func (s *index) prepareDocumentVectors(ctx context.Context, knowledgeBase models.KnowledgeBase, document models.KnowledgeDocument, chunks []ragchunk.ChunkResult) ([]vectordb.Vector, []models.KnowledgeChunk, int, error) {
|
||||||
vectors := make([]vectordb.Vector, 0, len(chunks))
|
vectors := make([]vectordb.Vector, 0, len(chunks))
|
||||||
chunkModels := make([]models.KnowledgeChunk, 0, len(chunks))
|
chunkModels := make([]models.KnowledgeChunk, 0, len(chunks))
|
||||||
dimension := 0
|
dimension := 0
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"cs-agent/internal/pkg/enums"
|
"cs-agent/internal/pkg/enums"
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildFAQChunkModel(knowledgeBase *models.KnowledgeBase, faq *models.KnowledgeFAQ, content string) (models.KnowledgeChunk, string) {
|
func buildFAQChunkModel(knowledgeBase models.KnowledgeBase, faq models.KnowledgeFAQ, content string) (models.KnowledgeChunk, string) {
|
||||||
chunkID := buildKnowledgeFAQChunkVectorID(knowledgeBase.ID, faq.ID, 0)
|
chunkID := buildKnowledgeFAQChunkVectorID(knowledgeBase.ID, faq.ID, 0)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
return models.KnowledgeChunk{
|
return models.KnowledgeChunk{
|
||||||
@@ -32,7 +32,7 @@ func buildFAQChunkModel(knowledgeBase *models.KnowledgeBase, faq *models.Knowled
|
|||||||
}, chunkID
|
}, chunkID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *index) prepareFAQVector(ctx context.Context, knowledgeBase *models.KnowledgeBase, faq *models.KnowledgeFAQ, content string) (vectordb.Vector, models.KnowledgeChunk, int, error) {
|
func (s *index) prepareFAQVector(ctx context.Context, knowledgeBase models.KnowledgeBase, faq models.KnowledgeFAQ, content string) (vectordb.Vector, models.KnowledgeChunk, int, error) {
|
||||||
embeddingResult, err := ai.Embedding.GenerateEmbedding(ctx, content)
|
embeddingResult, err := ai.Embedding.GenerateEmbedding(ctx, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vectordb.Vector{}, models.KnowledgeChunk{}, 0, fmt.Errorf("failed to generate embedding for faq %d: %w", faq.ID, err)
|
return vectordb.Vector{}, models.KnowledgeChunk{}, 0, fmt.Errorf("failed to generate embedding for faq %d: %w", faq.ID, err)
|
||||||
|
|||||||
@@ -10,43 +10,37 @@ import (
|
|||||||
"github.com/mlogclub/simple/sqls"
|
"github.com/mlogclub/simple/sqls"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *index) loadDocumentByID(documentID int64) (*models.KnowledgeDocument, error) {
|
func (s *index) loadDocumentByID(documentID int64) (models.KnowledgeDocument, error) {
|
||||||
document := repositories.KnowledgeDocumentRepository.Get(sqls.DB(), documentID)
|
document := repositories.KnowledgeDocumentRepository.Get(sqls.DB(), documentID)
|
||||||
if document == nil {
|
if document == nil {
|
||||||
return nil, fmt.Errorf("document not found: %d", documentID)
|
return models.KnowledgeDocument{}, fmt.Errorf("document not found: %d", documentID)
|
||||||
}
|
}
|
||||||
return document, nil
|
return *document, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *index) loadFAQByID(faqID int64) (*models.KnowledgeFAQ, error) {
|
func (s *index) loadFAQByID(faqID int64) (models.KnowledgeFAQ, error) {
|
||||||
faq := repositories.KnowledgeFAQRepository.Get(sqls.DB(), faqID)
|
faq := repositories.KnowledgeFAQRepository.Get(sqls.DB(), faqID)
|
||||||
if faq == nil {
|
if faq == nil {
|
||||||
return nil, fmt.Errorf("faq not found: %d", faqID)
|
return models.KnowledgeFAQ{}, fmt.Errorf("faq not found: %d", faqID)
|
||||||
}
|
}
|
||||||
return faq, nil
|
return *faq, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *index) loadDocumentKnowledgeBase(document *models.KnowledgeDocument) (*models.KnowledgeBase, error) {
|
func (s *index) loadDocumentKnowledgeBase(document models.KnowledgeDocument) (models.KnowledgeBase, error) {
|
||||||
if document == nil {
|
|
||||||
return nil, fmt.Errorf("document is nil")
|
|
||||||
}
|
|
||||||
knowledgeBase := repositories.KnowledgeBaseRepository.Get(sqls.DB(), document.KnowledgeBaseID)
|
knowledgeBase := repositories.KnowledgeBaseRepository.Get(sqls.DB(), document.KnowledgeBaseID)
|
||||||
if knowledgeBase == nil {
|
if knowledgeBase == nil {
|
||||||
return nil, fmt.Errorf("knowledge base not found: %d", document.KnowledgeBaseID)
|
return models.KnowledgeBase{}, fmt.Errorf("knowledge base not found: %d", document.KnowledgeBaseID)
|
||||||
}
|
}
|
||||||
return knowledgeBase, nil
|
return *knowledgeBase, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *index) loadFAQKnowledgeBase(faq *models.KnowledgeFAQ) (*models.KnowledgeBase, error) {
|
func (s *index) loadFAQKnowledgeBase(faq models.KnowledgeFAQ) (models.KnowledgeBase, error) {
|
||||||
if faq == nil {
|
|
||||||
return nil, fmt.Errorf("faq is nil")
|
|
||||||
}
|
|
||||||
knowledgeBase := repositories.KnowledgeBaseRepository.Get(sqls.DB(), faq.KnowledgeBaseID)
|
knowledgeBase := repositories.KnowledgeBaseRepository.Get(sqls.DB(), faq.KnowledgeBaseID)
|
||||||
if knowledgeBase == nil {
|
if knowledgeBase == nil {
|
||||||
return nil, fmt.Errorf("knowledge base not found: %d", faq.KnowledgeBaseID)
|
return models.KnowledgeBase{}, fmt.Errorf("knowledge base not found: %d", faq.KnowledgeBaseID)
|
||||||
}
|
}
|
||||||
if knowledgeBase.KnowledgeType != string(enums.KnowledgeBaseTypeFAQ) {
|
if knowledgeBase.KnowledgeType != string(enums.KnowledgeBaseTypeFAQ) {
|
||||||
return nil, fmt.Errorf("knowledge base %d is not faq type", knowledgeBase.ID)
|
return models.KnowledgeBase{}, fmt.Errorf("knowledge base %d is not faq type", knowledgeBase.ID)
|
||||||
}
|
}
|
||||||
return knowledgeBase, nil
|
return *knowledgeBase, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestBuildFAQChunkContent(t *testing.T) {
|
func TestBuildFAQChunkContent(t *testing.T) {
|
||||||
faq := &models.KnowledgeFAQ{
|
faq := models.KnowledgeFAQ{
|
||||||
Question: "如何退款",
|
Question: "如何退款",
|
||||||
SimilarQuestions: `["退款怎么申请","申请售后"]`,
|
SimilarQuestions: `["退款怎么申请","申请售后"]`,
|
||||||
Answer: "在订单页发起退款。",
|
Answer: "在订单页发起退款。",
|
||||||
@@ -27,8 +27,8 @@ func TestBuildFAQChunkContent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildFAQChunkModel(t *testing.T) {
|
func TestBuildFAQChunkModel(t *testing.T) {
|
||||||
knowledgeBase := &models.KnowledgeBase{ID: 11}
|
knowledgeBase := models.KnowledgeBase{ID: 11}
|
||||||
faq := &models.KnowledgeFAQ{ID: 22, Question: "如何退款"}
|
faq := models.KnowledgeFAQ{ID: 22, Question: "如何退款"}
|
||||||
|
|
||||||
chunk, chunkID := buildFAQChunkModel(knowledgeBase, faq, "问题:如何退款\n回答:在订单页发起退款。")
|
chunk, chunkID := buildFAQChunkModel(knowledgeBase, faq, "问题:如何退款\n回答:在订单页发起退款。")
|
||||||
if chunkID == "" {
|
if chunkID == "" {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/mlogclub/simple/sqls"
|
"github.com/mlogclub/simple/sqls"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *index) runDocumentIndex(ctx context.Context, document *models.KnowledgeDocument, knowledgeBase *models.KnowledgeBase) ([]vectordb.Vector, int, error) {
|
func (s *index) runDocumentIndex(ctx context.Context, document models.KnowledgeDocument, knowledgeBase models.KnowledgeBase) ([]vectordb.Vector, int, error) {
|
||||||
existingChunks := repositories.KnowledgeChunkRepository.FindByDocumentID(sqls.DB(), document.ID)
|
existingChunks := repositories.KnowledgeChunkRepository.FindByDocumentID(sqls.DB(), document.ID)
|
||||||
chunks, err := s.buildDocumentChunks(ctx, document, knowledgeBase)
|
chunks, err := s.buildDocumentChunks(ctx, document, knowledgeBase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -51,7 +51,7 @@ func (s *index) runDocumentIndex(ctx context.Context, document *models.Knowledge
|
|||||||
return vectors, len(chunks), nil
|
return vectors, len(chunks), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *index) runFAQIndex(ctx context.Context, faq *models.KnowledgeFAQ, knowledgeBase *models.KnowledgeBase) error {
|
func (s *index) runFAQIndex(ctx context.Context, faq models.KnowledgeFAQ, knowledgeBase models.KnowledgeBase) error {
|
||||||
existingChunks := repositories.KnowledgeChunkRepository.FindByFaqID(sqls.DB(), faq.ID)
|
existingChunks := repositories.KnowledgeChunkRepository.FindByFaqID(sqls.DB(), faq.ID)
|
||||||
content := buildFAQChunkContent(faq)
|
content := buildFAQChunkContent(faq)
|
||||||
if content == "" {
|
if content == "" {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
applicationruntime "cs-agent/internal/ai/application/runtime"
|
||||||
|
"cs-agent/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type aiReplyContext struct {
|
||||||
|
Conversation models.Conversation
|
||||||
|
Message models.Message
|
||||||
|
AIAgent models.AIAgent
|
||||||
|
Trace *aiReplyTraceData
|
||||||
|
SummaryRef **applicationruntime.Summary
|
||||||
|
PendingInterrupt *models.ConversationInterrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c aiReplyContext) setSummary(summary *applicationruntime.Summary) {
|
||||||
|
if c.SummaryRef != nil {
|
||||||
|
*c.SummaryRef = summary
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
applicationruntime "cs-agent/internal/ai/application/runtime"
|
applicationruntime "cs-agent/internal/ai/application/runtime"
|
||||||
"cs-agent/internal/ai/runtime/graphs"
|
"cs-agent/internal/ai/runtime/graphs"
|
||||||
"cs-agent/internal/models"
|
|
||||||
svc "cs-agent/internal/services"
|
svc "cs-agent/internal/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,31 +15,30 @@ func newReplyInterruptService() *replyInterruptService {
|
|||||||
return &replyInterruptService{}
|
return &replyInterruptService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
|
func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owner *aiReplyService, replyCtx aiReplyContext) error {
|
||||||
pendingInterrupt *models.ConversationInterrupt, trace *aiReplyTraceData, summaryRef **applicationruntime.Summary) error {
|
if replyCtx.PendingInterrupt == nil || owner == nil {
|
||||||
if pendingInterrupt == nil || owner == nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
summary, err := owner.executor.ResumePendingInterrupt(ctx, runtimeReplyResumeInput{
|
summary, err := owner.executor.ResumePendingInterrupt(ctx, runtimeReplyResumeInput{
|
||||||
Conversation: conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
PendingInterrupt: pendingInterrupt,
|
PendingInterrupt: replyCtx.PendingInterrupt,
|
||||||
Trace: trace,
|
Trace: replyCtx.Trace,
|
||||||
})
|
})
|
||||||
*summaryRef = summary
|
replyCtx.setSummary(summary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isCheckpointMissingError(err) {
|
if isCheckpointMissingError(err) {
|
||||||
summary = expiredInterruptSummary()
|
summary = expiredInterruptSummary()
|
||||||
*summaryRef = summary
|
replyCtx.setSummary(summary)
|
||||||
trace.Status = "interrupt_expired"
|
replyCtx.Trace.Status = "interrupt_expired"
|
||||||
trace.FinalAction = "expired"
|
replyCtx.Trace.FinalAction = "expired"
|
||||||
replyMessage, expireErr := owner.commit.CommitAIReply(replyCommitInput{
|
replyMessage, expireErr := owner.commit.CommitAIReply(replyCommitInput{
|
||||||
Conversation: conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: summary.ReplyText,
|
ReplyText: summary.ReplyText,
|
||||||
Trace: trace,
|
Trace: replyCtx.Trace,
|
||||||
ClientPrefix: "ai_interrupt_expired",
|
ClientPrefix: "ai_interrupt_expired",
|
||||||
})
|
})
|
||||||
if expireErr != nil {
|
if expireErr != nil {
|
||||||
@@ -50,7 +48,7 @@ func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owne
|
|||||||
if replyMessage != nil {
|
if replyMessage != nil {
|
||||||
lastResumeMessageID = replyMessage.ID
|
lastResumeMessageID = replyMessage.ID
|
||||||
}
|
}
|
||||||
if expireMarkErr := svc.ConversationInterruptService.MarkExpired(pendingInterrupt.ID, lastResumeMessageID); expireMarkErr != nil {
|
if expireMarkErr := svc.ConversationInterruptService.MarkExpired(replyCtx.PendingInterrupt.ID, lastResumeMessageID); expireMarkErr != nil {
|
||||||
return expireMarkErr
|
return expireMarkErr
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -58,15 +56,15 @@ func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owne
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if summary != nil && summary.Interrupted {
|
if summary != nil && summary.Interrupted {
|
||||||
return s.HandleInterruptedResume(owner, conversation, message, aiAgent, pendingInterrupt, summary, trace)
|
return s.HandleInterruptedResume(owner, replyCtx, summary)
|
||||||
}
|
}
|
||||||
if summary != nil && strings.TrimSpace(summary.ReplyText) != "" {
|
if summary != nil && strings.TrimSpace(summary.ReplyText) != "" {
|
||||||
replyMessage, err := owner.commit.CommitAIReply(replyCommitInput{
|
replyMessage, err := owner.commit.CommitAIReply(replyCommitInput{
|
||||||
Conversation: conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: summary.ReplyText,
|
ReplyText: summary.ReplyText,
|
||||||
Trace: trace,
|
Trace: replyCtx.Trace,
|
||||||
ClientPrefix: "ai_resume",
|
ClientPrefix: "ai_resume",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -77,30 +75,29 @@ func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owne
|
|||||||
replyMessageID = replyMessage.ID
|
replyMessageID = replyMessage.ID
|
||||||
}
|
}
|
||||||
if graphs.IsCancellationReply(summary.ReplyText) {
|
if graphs.IsCancellationReply(summary.ReplyText) {
|
||||||
return svc.ConversationInterruptService.MarkCancelled(pendingInterrupt.ID, replyMessageID)
|
return svc.ConversationInterruptService.MarkCancelled(replyCtx.PendingInterrupt.ID, replyMessageID)
|
||||||
}
|
}
|
||||||
return svc.ConversationInterruptService.MarkResolved(pendingInterrupt.ID, replyMessageID)
|
return svc.ConversationInterruptService.MarkResolved(replyCtx.PendingInterrupt.ID, replyMessageID)
|
||||||
}
|
}
|
||||||
return svc.ConversationInterruptService.MarkResolved(pendingInterrupt.ID, 0)
|
return svc.ConversationInterruptService.MarkResolved(replyCtx.PendingInterrupt.ID, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *replyInterruptService) HandleInterruptedSummary(owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
|
func (s *replyInterruptService) HandleInterruptedSummary(owner *aiReplyService, replyCtx aiReplyContext, summary *applicationruntime.Summary) error {
|
||||||
summary *applicationruntime.Summary, trace *aiReplyTraceData) error {
|
|
||||||
if owner == nil {
|
if owner == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pending := buildConversationInterrupt(conversation, message, aiAgent, summary)
|
pending := buildConversationInterrupt(replyCtx.Conversation, replyCtx.Message, replyCtx.AIAgent, summary)
|
||||||
if err := svc.ConversationInterruptService.CreateOrUpdatePending(pending); err != nil {
|
if err := svc.ConversationInterruptService.CreateOrUpdatePending(pending); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pending = svc.ConversationInterruptService.GetByCheckPointID(summary.CheckPointID)
|
pending = svc.ConversationInterruptService.GetByCheckPointID(summary.CheckPointID)
|
||||||
replyText := resolveInterruptPrompt(summary)
|
replyText := resolveInterruptPrompt(summary)
|
||||||
replyMessage, err := owner.commit.CommitAIReply(replyCommitInput{
|
replyMessage, err := owner.commit.CommitAIReply(replyCommitInput{
|
||||||
Conversation: conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: replyText,
|
ReplyText: replyText,
|
||||||
Trace: trace,
|
Trace: replyCtx.Trace,
|
||||||
ClientPrefix: "ai_interrupt",
|
ClientPrefix: "ai_interrupt",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -112,25 +109,24 @@ func (s *replyInterruptService) HandleInterruptedSummary(owner *aiReplyService,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *replyInterruptService) HandleInterruptedResume(owner *aiReplyService, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
|
func (s *replyInterruptService) HandleInterruptedResume(owner *aiReplyService, replyCtx aiReplyContext, summary *applicationruntime.Summary) error {
|
||||||
pendingInterrupt *models.ConversationInterrupt, summary *applicationruntime.Summary, trace *aiReplyTraceData) error {
|
if replyCtx.PendingInterrupt == nil || owner == nil {
|
||||||
if pendingInterrupt == nil || owner == nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
replyText := resolveInterruptPrompt(summary)
|
replyText := resolveInterruptPrompt(summary)
|
||||||
replyMessage, err := owner.commit.CommitAIReply(replyCommitInput{
|
replyMessage, err := owner.commit.CommitAIReply(replyCommitInput{
|
||||||
Conversation: conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: replyText,
|
ReplyText: replyText,
|
||||||
Trace: trace,
|
Trace: replyCtx.Trace,
|
||||||
ClientPrefix: "ai_interrupt_resume",
|
ClientPrefix: "ai_interrupt_resume",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if replyMessage != nil {
|
if replyMessage != nil {
|
||||||
return svc.ConversationInterruptService.MarkPendingAgain(pendingInterrupt.ID, firstInterruptID(summary), replyText, replyMessage.ID)
|
return svc.ConversationInterruptService.MarkPendingAgain(replyCtx.PendingInterrupt.ID, firstInterruptID(summary), replyText, replyMessage.ID)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ func (s *aiReplyService) TriggerReply(ctx context.Context, conversation models.C
|
|||||||
startedAt := time.Now()
|
startedAt := time.Now()
|
||||||
trace := &aiReplyTraceData{Status: "started"}
|
trace := &aiReplyTraceData{Status: "started"}
|
||||||
var summary *applicationruntime.Summary
|
var summary *applicationruntime.Summary
|
||||||
|
replyCtx := aiReplyContext{
|
||||||
|
Conversation: conversation,
|
||||||
|
Message: message,
|
||||||
|
AIAgent: aiAgent,
|
||||||
|
Trace: trace,
|
||||||
|
SummaryRef: &summary,
|
||||||
|
}
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -65,46 +72,43 @@ func (s *aiReplyService) TriggerReply(ctx context.Context, conversation models.C
|
|||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
if pendingInterrupt := svc.ConversationInterruptService.FindLatestPendingByConversationID(conversation.ID); pendingInterrupt != nil {
|
if pendingInterrupt := svc.ConversationInterruptService.FindLatestPendingByConversationID(conversation.ID); pendingInterrupt != nil {
|
||||||
return s.resumePendingInterrupt(ctx, conversation, message, aiAgent, pendingInterrupt, trace, &summary)
|
replyCtx.PendingInterrupt = pendingInterrupt
|
||||||
|
return s.resumePendingInterrupt(ctx, replyCtx)
|
||||||
}
|
}
|
||||||
return s.executeReply(ctx, conversation, message, aiAgent, trace, &summary)
|
return s.executeReply(ctx, replyCtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *aiReplyService) resumePendingInterrupt(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
|
func (s *aiReplyService) resumePendingInterrupt(ctx context.Context, replyCtx aiReplyContext) error {
|
||||||
pendingInterrupt *models.ConversationInterrupt, trace *aiReplyTraceData, summaryRef **applicationruntime.Summary) error {
|
return s.interrupts.ResumePendingInterrupt(ctx, s, replyCtx)
|
||||||
return s.interrupts.ResumePendingInterrupt(ctx, s, conversation, message, aiAgent, pendingInterrupt, trace, summaryRef)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *aiReplyService) executeReply(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent,
|
func (s *aiReplyService) executeReply(ctx context.Context, replyCtx aiReplyContext) error {
|
||||||
trace *aiReplyTraceData, summaryRef **applicationruntime.Summary) error {
|
|
||||||
summary, err := s.executor.Run(ctx, runtimeReplyRunInput{
|
summary, err := s.executor.Run(ctx, runtimeReplyRunInput{
|
||||||
Conversation: conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
Trace: trace,
|
Trace: replyCtx.Trace,
|
||||||
})
|
})
|
||||||
if summaryRef != nil {
|
replyCtx.setSummary(summary)
|
||||||
*summaryRef = summary
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if summary != nil && summary.Interrupted {
|
if summary != nil && summary.Interrupted {
|
||||||
return s.interrupts.HandleInterruptedSummary(s, conversation, message, aiAgent, summary, trace)
|
return s.interrupts.HandleInterruptedSummary(s, replyCtx, summary)
|
||||||
}
|
}
|
||||||
if summary != nil && strings.TrimSpace(summary.ReplyText) != "" {
|
if summary != nil && strings.TrimSpace(summary.ReplyText) != "" {
|
||||||
replyMessage, err := s.commit.CommitAIReply(replyCommitInput{
|
replyMessage, err := s.commit.CommitAIReply(replyCommitInput{
|
||||||
Conversation: conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: summary.ReplyText,
|
ReplyText: summary.ReplyText,
|
||||||
Trace: trace,
|
Trace: replyCtx.Trace,
|
||||||
ClientPrefix: "ai_reply",
|
ClientPrefix: "ai_reply",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
trace.ReplySent = replyMessage != nil
|
replyCtx.Trace.ReplySent = replyMessage != nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user