Version: 0.8.1.dev.260326

后端:
1.获取agent聊天历史记录接口做了如下更改:
(1)对reasoning_content也做了存储,同步更改了mysql和redis缓存的读写逻辑
(2)为了承接前端的重试/修改消息的逻辑,进行了一些代码和表单上的改动
前端:
1.agent页面新增了很多小组件,改善交互体验
2.新增重试消息/修改消息并重新发送功能,前者有bug,可能前后端都有问题,待修复。
This commit is contained in:
Losita
2026-03-26 22:15:16 +08:00
parent ddf4c09f69
commit ddb0d9cc17
13 changed files with 1828 additions and 322 deletions

View File

@@ -45,7 +45,7 @@ func (s *AgentService) GetConversationHistory(ctx context.Context, userID int, c
history, cacheErr := s.agentCache.GetHistory(ctx, normalizedChatID)
if cacheErr != nil {
log.Printf("读取会话历史缓存失败 chat_id=%s: %v", normalizedChatID, cacheErr)
} else if history != nil {
} else if history != nil && !cacheConversationHistoryHasRetryMetadata(history) {
return buildConversationHistoryItemsFromCache(history), nil
}
}
@@ -81,12 +81,15 @@ func buildConversationHistoryItemsFromCache(messages []*schema.Message) []model.
continue
}
items = append(items, model.GetConversationHistoryItem{
Role: normalizeConversationHistoryRole(string(msg.Role)),
Content: strings.TrimSpace(msg.Content),
ReasoningContent: strings.TrimSpace(msg.ReasoningContent),
Role: normalizeConversationHistoryRole(string(msg.Role)),
Content: strings.TrimSpace(msg.Content),
ReasoningContent: strings.TrimSpace(msg.ReasoningContent),
ReasoningDurationSeconds: extractConversationReasoningDurationSeconds(msg),
RetryGroupID: extractConversationRetryGroupID(msg),
RetryIndex: extractConversationRetryIndex(msg),
})
}
return items
return attachConversationRetryTotals(items)
}
// buildConversationHistoryItemsFromDB 把数据库聊天记录转换为接口响应。
@@ -109,15 +112,156 @@ func buildConversationHistoryItemsFromDB(histories []model.ChatHistory) []model.
}
items = append(items, model.GetConversationHistoryItem{
ID: history.ID,
Role: role,
Content: content,
CreatedAt: history.CreatedAt,
ID: history.ID,
Role: role,
Content: content,
CreatedAt: history.CreatedAt,
ReasoningContent: strings.TrimSpace(derefConversationHistoryText(history.ReasoningContent)),
ReasoningDurationSeconds: history.ReasoningDurationSeconds,
RetryGroupID: cloneConversationStringPointer(history.RetryGroupID),
RetryIndex: cloneConversationIntPointer(history.RetryIndex),
})
}
return attachConversationRetryTotals(items)
}
func derefConversationHistoryText(text *string) string {
if text == nil {
return ""
}
return *text
}
func extractConversationReasoningDurationSeconds(msg *schema.Message) int {
if msg == nil || msg.Extra == nil {
return 0
}
raw, ok := msg.Extra["reasoning_duration_seconds"]
if !ok {
return 0
}
switch v := raw.(type) {
case int:
return v
case int32:
return int(v)
case int64:
return int(v)
case float64:
return int(v)
default:
return 0
}
}
func extractConversationRetryGroupID(msg *schema.Message) *string {
if msg == nil || msg.Extra == nil {
return nil
}
raw, ok := msg.Extra["retry_group_id"]
if !ok {
return nil
}
text, ok := raw.(string)
if !ok {
return nil
}
text = strings.TrimSpace(text)
if text == "" {
return nil
}
return &text
}
func extractConversationRetryIndex(msg *schema.Message) *int {
if msg == nil || msg.Extra == nil {
return nil
}
raw, ok := msg.Extra["retry_index"]
if !ok {
return nil
}
switch v := raw.(type) {
case int:
if v <= 0 {
return nil
}
return &v
case int32:
value := int(v)
if value <= 0 {
return nil
}
return &value
case int64:
value := int(v)
if value <= 0 {
return nil
}
return &value
case float64:
value := int(v)
if value <= 0 {
return nil
}
return &value
default:
return nil
}
}
func attachConversationRetryTotals(items []model.GetConversationHistoryItem) []model.GetConversationHistoryItem {
if len(items) == 0 {
return items
}
groupTotals := make(map[string]int)
for _, item := range items {
if item.RetryGroupID == nil || item.RetryIndex == nil {
continue
}
groupID := strings.TrimSpace(*item.RetryGroupID)
if groupID == "" {
continue
}
if *item.RetryIndex > groupTotals[groupID] {
groupTotals[groupID] = *item.RetryIndex
}
}
for idx := range items {
groupIDPtr := items[idx].RetryGroupID
if groupIDPtr == nil {
continue
}
groupID := strings.TrimSpace(*groupIDPtr)
total := groupTotals[groupID]
if total <= 0 {
continue
}
totalCopy := total
items[idx].RetryTotal = &totalCopy
}
return items
}
func cloneConversationStringPointer(src *string) *string {
if src == nil {
return nil
}
text := strings.TrimSpace(*src)
if text == "" {
return nil
}
return &text
}
func cloneConversationIntPointer(src *int) *int {
if src == nil || *src <= 0 {
return nil
}
value := *src
return &value
}
func normalizeConversationHistoryRole(role string) string {
switch strings.ToLower(strings.TrimSpace(role)) {
case "user":
@@ -128,3 +272,12 @@ func normalizeConversationHistoryRole(role string) string {
return "system"
}
}
func cacheConversationHistoryHasRetryMetadata(messages []*schema.Message) bool {
for _, msg := range messages {
if extractConversationRetryGroupID(msg) != nil {
return true
}
}
return false
}