This commit is contained in:
2026-06-10 07:55:16 +08:00
parent 821eca9f0c
commit aaac7e9d98
31 changed files with 548 additions and 149 deletions
+29 -17
View File
@@ -161,8 +161,8 @@ func (s *messageService) Send(
TargetType: "message",
TargetID: int64ToString(userMsg.ID),
Metadata: map[string]any{
"conversation_id": conversationID.String(),
"attachment_count": len(atts),
"conversation_id": conversationID.String(),
"attachment_count": len(atts),
},
})
@@ -301,25 +301,25 @@ func (s *messageService) Cancel(ctx context.Context, userID uuid.UUID, messageID
// Retry deletes the failed/cancelled assistant message, inserts a fresh pending
// one, and restarts the streamer.
func (s *messageService) Retry(ctx context.Context, userID uuid.UUID, messageID int64) (int64, error) {
func (s *messageService) Retry(ctx context.Context, userID uuid.UUID, messageID int64) (int64, uuid.UUID, error) {
old, err := s.repo.GetMessage(ctx, messageID)
if err != nil {
return 0, err
return 0, uuid.Nil, err
}
if old.Status != StatusError && old.Status != StatusCancelled {
return 0, errs.New(errs.CodeChatMessageNotPending, "message is not retriable")
return 0, uuid.Nil, errs.New(errs.CodeChatMessageNotPending, "message is not retriable")
}
conv, err := s.repo.GetConversation(ctx, old.ConversationID)
if err != nil {
return 0, err
return 0, uuid.Nil, err
}
if conv.UserID != userID {
return 0, errs.New(errs.CodeForbidden, "not conversation owner")
return 0, uuid.Nil, errs.New(errs.CodeForbidden, "not conversation owner")
}
repo, tx, err := s.repo.WithTx(ctx)
if err != nil {
return 0, err
return 0, uuid.Nil, err
}
committed := false
defer func() {
@@ -329,15 +329,15 @@ func (s *messageService) Retry(ctx context.Context, userID uuid.UUID, messageID
}()
if err := repo.DeleteMessage(ctx, messageID); err != nil {
return 0, err
return 0, uuid.Nil, err
}
asstMsg, err := repo.InsertMessage(ctx, conv.ID, RoleAssistant, "", StatusPending)
if err != nil {
return 0, err
return 0, uuid.Nil, err
}
if err := tx.Commit(ctx); err != nil {
return 0, err
return 0, uuid.Nil, err
}
committed = true
@@ -345,20 +345,20 @@ func (s *messageService) Retry(ctx context.Context, userID uuid.UUID, messageID
if err != nil {
e := err.Error()
_ = s.repo.UpdateMessageError(ctx, asstMsg.ID, &e)
return asstMsg.ID, err
return asstMsg.ID, conv.ID, err
}
endpoint, err := s.repo.GetLLMEndpoint(ctx, model.EndpointID)
if err != nil {
e := err.Error()
_ = s.repo.UpdateMessageError(ctx, asstMsg.ID, &e)
return asstMsg.ID, err
return asstMsg.ID, conv.ID, err
}
req, err := s.composeHistory(ctx, conv, model)
if err != nil {
e := err.Error()
_ = s.repo.UpdateMessageError(ctx, asstMsg.ID, &e)
return asstMsg.ID, err
return asstMsg.ID, conv.ID, err
}
params := StreamParams{
@@ -373,7 +373,7 @@ func (s *messageService) Retry(ctx context.Context, userID uuid.UUID, messageID
if err := s.hub.Start(ctx, params); err != nil {
e := err.Error()
_ = s.repo.UpdateMessageError(ctx, asstMsg.ID, &e)
return asstMsg.ID, err
return asstMsg.ID, conv.ID, err
}
// Audit after successful hub start.
@@ -388,7 +388,7 @@ func (s *messageService) Retry(ctx context.Context, userID uuid.UUID, messageID
},
})
return asstMsg.ID, nil
return asstMsg.ID, conv.ID, nil
}
// ListMessages returns paginated messages for a conversation, enforcing ownership.
@@ -408,7 +408,19 @@ func (s *messageService) ListMessages(
if limit == 0 || limit > 200 {
limit = 50
}
return s.repo.ListMessagesByConversation(ctx, conversationID, beforeID, limit)
msgs, err := s.repo.ListMessagesByConversation(ctx, conversationID, beforeID, limit)
if err != nil {
return nil, err
}
// Populate each message's attachments for the user-facing read path.
for i := range msgs {
atts, err := s.repo.ListAttachmentsForMessage(ctx, msgs[i].ID)
if err != nil {
return nil, err
}
msgs[i].Attachments = atts
}
return msgs, nil
}
// composeHistory loads all OK/Pending messages for the conversation, fetches