From 8b4227111ff6df2ba095ea043b706b285338c9b0 Mon Sep 17 00:00:00 2001
From: 1 <1@123>
Date: 星期一, 23 三月 2026 13:26:06 +0800
Subject: [PATCH] lsh#

---
 rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java |  516 +-------------------------------------------------------
 1 files changed, 14 insertions(+), 502 deletions(-)

diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java
index 5f1c1f3..3caec94 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java
@@ -1,556 +1,68 @@
 package com.vincent.rsf.server.ai.service.impl;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.vincent.rsf.framework.common.Cools;
-import com.vincent.rsf.framework.exception.CoolException;
-import com.vincent.rsf.server.ai.config.AiDefaults;
 import com.vincent.rsf.server.ai.dto.AiChatMemoryDto;
 import com.vincent.rsf.server.ai.dto.AiChatMessageDto;
+import com.vincent.rsf.server.ai.dto.AiChatSessionDto;
 import com.vincent.rsf.server.ai.dto.AiChatSessionPinRequest;
 import com.vincent.rsf.server.ai.dto.AiChatSessionRenameRequest;
-import com.vincent.rsf.server.ai.dto.AiChatSessionDto;
-import com.vincent.rsf.server.ai.entity.AiChatMessage;
 import com.vincent.rsf.server.ai.entity.AiChatSession;
-import com.vincent.rsf.server.ai.mapper.AiChatMessageMapper;
-import com.vincent.rsf.server.ai.mapper.AiChatSessionMapper;
 import com.vincent.rsf.server.ai.service.AiChatMemoryService;
-import com.vincent.rsf.server.system.enums.StatusType;
+import com.vincent.rsf.server.ai.service.impl.conversation.AiConversationCommandService;
+import com.vincent.rsf.server.ai.service.impl.conversation.AiConversationQueryService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
 
-import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
 @Service
 @RequiredArgsConstructor
 public class AiChatMemoryServiceImpl implements AiChatMemoryService {
 
-    private final AiChatSessionMapper aiChatSessionMapper;
-    private final AiChatMessageMapper aiChatMessageMapper;
+    private final AiConversationQueryService aiConversationQueryService;
+    private final AiConversationCommandService aiConversationCommandService;
 
     @Override
     public AiChatMemoryDto getMemory(Long userId, Long tenantId, String promptCode, Long sessionId) {
-        ensureIdentity(userId, tenantId);
-        String resolvedPromptCode = requirePromptCode(promptCode);
-        AiChatSession session = sessionId == null
-                ? findLatestSession(userId, tenantId, resolvedPromptCode)
-                : getSession(sessionId, userId, tenantId, resolvedPromptCode);
-        if (session == null) {
-            return AiChatMemoryDto.builder()
-                    .sessionId(null)
-                    .memorySummary(null)
-                    .memoryFacts(null)
-                    .recentMessageCount(0)
-                    .persistedMessages(List.of())
-                    .shortMemoryMessages(List.of())
-                    .build();
-        }
-        List<AiChatMessageDto> persistedMessages = listMessages(session.getId());
-        List<AiChatMessageDto> shortMemoryMessages = tailMessagesByRounds(persistedMessages, AiDefaults.MEMORY_RECENT_ROUNDS);
-        return AiChatMemoryDto.builder()
-                .sessionId(session.getId())
-                .memorySummary(session.getMemorySummary())
-                .memoryFacts(session.getMemoryFacts())
-                .recentMessageCount(shortMemoryMessages.size())
-                .persistedMessages(persistedMessages)
-                .shortMemoryMessages(shortMemoryMessages)
-                .build();
+        return aiConversationQueryService.getMemory(userId, tenantId, promptCode, sessionId);
     }
 
     @Override
     public List<AiChatSessionDto> listSessions(Long userId, Long tenantId, String promptCode, String keyword) {
-        ensureIdentity(userId, tenantId);
-        String resolvedPromptCode = requirePromptCode(promptCode);
-        List<AiChatSession> sessions = aiChatSessionMapper.selectList(new LambdaQueryWrapper<AiChatSession>()
-                .eq(AiChatSession::getUserId, userId)
-                .eq(AiChatSession::getTenantId, tenantId)
-                .eq(AiChatSession::getPromptCode, resolvedPromptCode)
-                .eq(AiChatSession::getDeleted, 0)
-                .eq(AiChatSession::getStatus, StatusType.ENABLE.val)
-                .like(StringUtils.hasText(keyword), AiChatSession::getTitle, keyword == null ? null : keyword.trim())
-                .orderByDesc(AiChatSession::getPinned)
-                .orderByDesc(AiChatSession::getLastMessageTime)
-                .orderByDesc(AiChatSession::getId));
-        if (Cools.isEmpty(sessions)) {
-            return List.of();
-        }
-        List<AiChatSessionDto> result = new ArrayList<>();
-        for (AiChatSession session : sessions) {
-            result.add(buildSessionDto(session));
-        }
-        return result;
+        return aiConversationQueryService.listSessions(userId, tenantId, promptCode, keyword);
     }
 
     @Override
     public AiChatSession resolveSession(Long userId, Long tenantId, String promptCode, Long sessionId, String titleSeed) {
-        ensureIdentity(userId, tenantId);
-        String resolvedPromptCode = requirePromptCode(promptCode);
-        if (sessionId != null) {
-            return getSession(sessionId, userId, tenantId, resolvedPromptCode);
-        }
-        Date now = new Date();
-        AiChatSession session = new AiChatSession()
-                .setTitle(buildSessionTitle(titleSeed))
-                .setPromptCode(resolvedPromptCode)
-                .setUserId(userId)
-                .setTenantId(tenantId)
-                .setLastMessageTime(now)
-                .setPinned(0)
-                .setStatus(StatusType.ENABLE.val)
-                .setDeleted(0)
-                .setCreateBy(userId)
-                .setCreateTime(now)
-                .setUpdateBy(userId)
-                .setUpdateTime(now);
-        aiChatSessionMapper.insert(session);
-        return session;
+        return aiConversationCommandService.resolveSession(userId, tenantId, promptCode, sessionId, titleSeed);
     }
 
     @Override
     public void saveRound(AiChatSession session, Long userId, Long tenantId, List<AiChatMessageDto> memoryMessages, String assistantContent) {
-        if (session == null || session.getId() == null) {
-            throw new CoolException("AI 浼氳瘽涓嶅瓨鍦�");
-        }
-        ensureIdentity(userId, tenantId);
-        List<AiChatMessageDto> normalizedMessages = normalizeMessages(memoryMessages);
-        if (normalizedMessages.isEmpty()) {
-            throw new CoolException("鏈疆娌℃湁鍙繚瀛樼殑瀵硅瘽娑堟伅");
-        }
-        int nextSeqNo = findNextSeqNo(session.getId());
-        Date now = new Date();
-        for (AiChatMessageDto message : normalizedMessages) {
-            aiChatMessageMapper.insert(buildMessageEntity(session.getId(), nextSeqNo++, message.getRole(), message.getContent(), userId, tenantId, now));
-        }
-        if (StringUtils.hasText(assistantContent)) {
-            aiChatMessageMapper.insert(buildMessageEntity(session.getId(), nextSeqNo, "assistant", assistantContent, userId, tenantId, now));
-        }
-        AiChatSession update = new AiChatSession()
-                .setId(session.getId())
-                .setTitle(resolveUpdatedTitle(session.getTitle(), normalizedMessages))
-                .setLastMessageTime(now)
-                .setUpdateBy(userId)
-                .setUpdateTime(now);
-        aiChatSessionMapper.updateById(update);
-        refreshMemoryProfile(session.getId(), userId);
+        aiConversationCommandService.saveRound(session, userId, tenantId, memoryMessages, assistantContent);
     }
 
     @Override
     public void removeSession(Long userId, Long tenantId, Long sessionId) {
-        ensureIdentity(userId, tenantId);
-        if (sessionId == null) {
-            throw new CoolException("AI 浼氳瘽 ID 涓嶈兘涓虹┖");
-        }
-        AiChatSession session = aiChatSessionMapper.selectOne(new LambdaQueryWrapper<AiChatSession>()
-                .eq(AiChatSession::getId, sessionId)
-                .eq(AiChatSession::getUserId, userId)
-                .eq(AiChatSession::getTenantId, tenantId)
-                .eq(AiChatSession::getDeleted, 0)
-                .last("limit 1"));
-        if (session == null) {
-            throw new CoolException("AI 浼氳瘽涓嶅瓨鍦ㄦ垨鏃犳潈鍒犻櫎");
-        }
-        Date now = new Date();
-        AiChatSession updateSession = new AiChatSession()
-                .setId(sessionId)
-                .setDeleted(1)
-                .setUpdateBy(userId)
-                .setUpdateTime(now);
-        aiChatSessionMapper.updateById(updateSession);
-        List<AiChatMessage> messages = aiChatMessageMapper.selectList(new LambdaQueryWrapper<AiChatMessage>()
-                .eq(AiChatMessage::getSessionId, sessionId)
-                .eq(AiChatMessage::getDeleted, 0));
-        for (AiChatMessage message : messages) {
-            AiChatMessage updateMessage = new AiChatMessage()
-                    .setId(message.getId())
-                    .setDeleted(1);
-            aiChatMessageMapper.updateById(updateMessage);
-        }
+        aiConversationCommandService.removeSession(userId, tenantId, sessionId);
     }
 
     @Override
     public AiChatSessionDto renameSession(Long userId, Long tenantId, Long sessionId, AiChatSessionRenameRequest request) {
-        ensureIdentity(userId, tenantId);
-        if (request == null || !StringUtils.hasText(request.getTitle())) {
-            throw new CoolException("浼氳瘽鏍囬涓嶈兘涓虹┖");
-        }
-        AiChatSession session = requireOwnedSession(sessionId, userId, tenantId);
-        Date now = new Date();
-        AiChatSession update = new AiChatSession()
-                .setId(sessionId)
-                .setTitle(buildSessionTitle(request.getTitle()))
-                .setUpdateBy(userId)
-                .setUpdateTime(now);
-        aiChatSessionMapper.updateById(update);
-        return buildSessionDto(requireOwnedSession(sessionId, userId, tenantId));
+        return aiConversationCommandService.renameSession(userId, tenantId, sessionId, request);
     }
 
     @Override
     public AiChatSessionDto pinSession(Long userId, Long tenantId, Long sessionId, AiChatSessionPinRequest request) {
-        ensureIdentity(userId, tenantId);
-        if (request == null || request.getPinned() == null) {
-            throw new CoolException("缃《鐘舵�佷笉鑳戒负绌�");
-        }
-        AiChatSession session = requireOwnedSession(sessionId, userId, tenantId);
-        Date now = new Date();
-        AiChatSession update = new AiChatSession()
-                .setId(sessionId)
-                .setPinned(Boolean.TRUE.equals(request.getPinned()) ? 1 : 0)
-                .setUpdateBy(userId)
-                .setUpdateTime(now);
-        aiChatSessionMapper.updateById(update);
-        return buildSessionDto(requireOwnedSession(sessionId, userId, tenantId));
+        return aiConversationCommandService.pinSession(userId, tenantId, sessionId, request);
     }
 
     @Override
     public void clearSessionMemory(Long userId, Long tenantId, Long sessionId) {
-        ensureIdentity(userId, tenantId);
-        AiChatSession session = requireOwnedSession(sessionId, userId, tenantId);
-        List<AiChatMessage> messages = aiChatMessageMapper.selectList(new LambdaQueryWrapper<AiChatMessage>()
-                .eq(AiChatMessage::getSessionId, sessionId)
-                .eq(AiChatMessage::getDeleted, 0));
-        for (AiChatMessage message : messages) {
-            aiChatMessageMapper.updateById(new AiChatMessage()
-                    .setId(message.getId())
-                    .setDeleted(1));
-        }
-        aiChatSessionMapper.updateById(new AiChatSession()
-                .setId(sessionId)
-                .setMemorySummary(null)
-                .setMemoryFacts(null)
-                .setUpdateBy(userId)
-                .setUpdateTime(new Date())
-                .setLastMessageTime(session.getCreateTime()));
+        aiConversationCommandService.clearSessionMemory(userId, tenantId, sessionId);
     }
 
     @Override
     public void retainLatestRound(Long userId, Long tenantId, Long sessionId) {
-        ensureIdentity(userId, tenantId);
-        requireOwnedSession(sessionId, userId, tenantId);
-        List<AiChatMessage> records = listMessageRecords(sessionId);
-        if (records.isEmpty()) {
-            return;
-        }
-        List<AiChatMessage> retained = tailMessageRecordsByRounds(records, 1);
-        for (AiChatMessage message : records) {
-            boolean shouldKeep = retained.stream().anyMatch(item -> item.getId().equals(message.getId()));
-            if (!shouldKeep) {
-                aiChatMessageMapper.updateById(new AiChatMessage()
-                        .setId(message.getId())
-                        .setDeleted(1));
-            }
-        }
-        refreshMemoryProfile(sessionId, userId);
-    }
-
-    private AiChatSession findLatestSession(Long userId, Long tenantId, String promptCode) {
-        return aiChatSessionMapper.selectOne(new LambdaQueryWrapper<AiChatSession>()
-                .eq(AiChatSession::getUserId, userId)
-                .eq(AiChatSession::getTenantId, tenantId)
-                .eq(AiChatSession::getPromptCode, promptCode)
-                .eq(AiChatSession::getDeleted, 0)
-                .eq(AiChatSession::getStatus, StatusType.ENABLE.val)
-                .orderByDesc(AiChatSession::getLastMessageTime)
-                .orderByDesc(AiChatSession::getId)
-                .last("limit 1"));
-    }
-
-    private AiChatSession getSession(Long sessionId, Long userId, Long tenantId, String promptCode) {
-        AiChatSession session = aiChatSessionMapper.selectOne(new LambdaQueryWrapper<AiChatSession>()
-                .eq(AiChatSession::getId, sessionId)
-                .eq(AiChatSession::getUserId, userId)
-                .eq(AiChatSession::getTenantId, tenantId)
-                .eq(AiChatSession::getPromptCode, promptCode)
-                .eq(AiChatSession::getDeleted, 0)
-                .eq(AiChatSession::getStatus, StatusType.ENABLE.val)
-                .last("limit 1"));
-        if (session == null) {
-            throw new CoolException("AI 浼氳瘽涓嶅瓨鍦ㄦ垨鏃犳潈璁块棶");
-        }
-        return session;
-    }
-
-    private AiChatSession requireOwnedSession(Long sessionId, Long userId, Long tenantId) {
-        if (sessionId == null) {
-            throw new CoolException("AI 浼氳瘽 ID 涓嶈兘涓虹┖");
-        }
-        AiChatSession session = aiChatSessionMapper.selectOne(new LambdaQueryWrapper<AiChatSession>()
-                .eq(AiChatSession::getId, sessionId)
-                .eq(AiChatSession::getUserId, userId)
-                .eq(AiChatSession::getTenantId, tenantId)
-                .eq(AiChatSession::getDeleted, 0)
-                .eq(AiChatSession::getStatus, StatusType.ENABLE.val)
-                .last("limit 1"));
-        if (session == null) {
-            throw new CoolException("AI 浼氳瘽涓嶅瓨鍦ㄦ垨鏃犳潈璁块棶");
-        }
-        return session;
-    }
-
-    private List<AiChatMessageDto> listMessages(Long sessionId) {
-        List<AiChatMessage> records = listMessageRecords(sessionId);
-        if (Cools.isEmpty(records)) {
-            return List.of();
-        }
-        List<AiChatMessageDto> messages = new ArrayList<>();
-        for (AiChatMessage record : records) {
-            if (!StringUtils.hasText(record.getContent())) {
-                continue;
-            }
-            AiChatMessageDto item = new AiChatMessageDto();
-            item.setRole(record.getRole());
-            item.setContent(record.getContent());
-            messages.add(item);
-        }
-        return messages;
-    }
-
-    private List<AiChatMessageDto> normalizeMessages(List<AiChatMessageDto> memoryMessages) {
-        List<AiChatMessageDto> normalized = new ArrayList<>();
-        if (Cools.isEmpty(memoryMessages)) {
-            return normalized;
-        }
-        for (AiChatMessageDto item : memoryMessages) {
-            if (item == null || !StringUtils.hasText(item.getContent())) {
-                continue;
-            }
-            String role = item.getRole() == null ? "user" : item.getRole().toLowerCase();
-            if ("system".equals(role)) {
-                continue;
-            }
-            AiChatMessageDto normalizedItem = new AiChatMessageDto();
-            normalizedItem.setRole("assistant".equals(role) ? "assistant" : "user");
-            normalizedItem.setContent(item.getContent().trim());
-            normalized.add(normalizedItem);
-        }
-        return normalized;
-    }
-
-    private List<AiChatMessage> listMessageRecords(Long sessionId) {
-        return aiChatMessageMapper.selectList(new LambdaQueryWrapper<AiChatMessage>()
-                .eq(AiChatMessage::getSessionId, sessionId)
-                .eq(AiChatMessage::getDeleted, 0)
-                .orderByAsc(AiChatMessage::getSeqNo)
-                .orderByAsc(AiChatMessage::getId));
-    }
-
-    private int findNextSeqNo(Long sessionId) {
-        AiChatMessage lastMessage = aiChatMessageMapper.selectOne(new LambdaQueryWrapper<AiChatMessage>()
-                .eq(AiChatMessage::getSessionId, sessionId)
-                .eq(AiChatMessage::getDeleted, 0)
-                .orderByDesc(AiChatMessage::getSeqNo)
-                .orderByDesc(AiChatMessage::getId)
-                .last("limit 1"));
-        return lastMessage == null || lastMessage.getSeqNo() == null ? 1 : lastMessage.getSeqNo() + 1;
-    }
-
-    private AiChatMessage buildMessageEntity(Long sessionId, int seqNo, String role, String content, Long userId, Long tenantId, Date createTime) {
-        return new AiChatMessage()
-                .setSessionId(sessionId)
-                .setSeqNo(seqNo)
-                .setRole(role)
-                .setContent(content)
-                .setContentLength(content == null ? 0 : content.length())
-                .setUserId(userId)
-                .setTenantId(tenantId)
-                .setDeleted(0)
-                .setCreateBy(userId)
-                .setCreateTime(createTime);
-    }
-
-    private String resolveUpdatedTitle(String currentTitle, List<AiChatMessageDto> memoryMessages) {
-        if (StringUtils.hasText(currentTitle)) {
-            return currentTitle;
-        }
-        for (AiChatMessageDto item : memoryMessages) {
-            if ("user".equals(item.getRole()) && StringUtils.hasText(item.getContent())) {
-                return buildSessionTitle(item.getContent());
-            }
-        }
-        return null;
-    }
-
-    private String buildSessionTitle(String titleSeed) {
-        if (!StringUtils.hasText(titleSeed)) {
-            throw new CoolException("AI 浼氳瘽鏍囬涓嶈兘涓虹┖");
-        }
-        String title = titleSeed.trim()
-                .replace("\r", " ")
-                .replace("\n", " ")
-                .replaceAll("\\s+", " ");
-        int punctuationIndex = findSummaryBreakIndex(title);
-        if (punctuationIndex > 0) {
-            title = title.substring(0, punctuationIndex).trim();
-        }
-        return title.length() > 48 ? title.substring(0, 48) : title;
-    }
-
-    private int findSummaryBreakIndex(String title) {
-        String[] separators = {"銆�", "锛�", "锛�", ".", "!", "?"};
-        int result = -1;
-        for (String separator : separators) {
-            int index = title.indexOf(separator);
-            if (index > 0 && (result < 0 || index < result)) {
-                result = index;
-            }
-        }
-        return result;
-    }
-
-    private AiChatSessionDto buildSessionDto(AiChatSession session) {
-        AiChatMessage lastMessage = aiChatMessageMapper.selectOne(new LambdaQueryWrapper<AiChatMessage>()
-                .eq(AiChatMessage::getSessionId, session.getId())
-                .eq(AiChatMessage::getDeleted, 0)
-                .orderByDesc(AiChatMessage::getSeqNo)
-                .orderByDesc(AiChatMessage::getId)
-                .last("limit 1"));
-        return AiChatSessionDto.builder()
-                .sessionId(session.getId())
-                .title(session.getTitle())
-                .promptCode(session.getPromptCode())
-                .pinned(session.getPinned() != null && session.getPinned() == 1)
-                .lastMessagePreview(buildLastMessagePreview(lastMessage))
-                .lastMessageTime(session.getLastMessageTime())
-                .build();
-    }
-
-    private String buildLastMessagePreview(AiChatMessage message) {
-        if (message == null || !StringUtils.hasText(message.getContent())) {
-            return null;
-        }
-        String preview = message.getContent().trim()
-                .replace("\r", " ")
-                .replace("\n", " ")
-                .replaceAll("\\s+", " ");
-        String prefix = "assistant".equalsIgnoreCase(message.getRole()) ? "AI: " : "浣�: ";
-        String normalized = prefix + preview;
-        return normalized.length() > 80 ? normalized.substring(0, 80) : normalized;
-    }
-
-    private void refreshMemoryProfile(Long sessionId, Long userId) {
-        List<AiChatMessageDto> messages = listMessages(sessionId);
-        List<AiChatMessageDto> shortMemoryMessages = tailMessagesByRounds(messages, AiDefaults.MEMORY_RECENT_ROUNDS);
-        List<AiChatMessageDto> historyMessages = messages.size() > shortMemoryMessages.size()
-                ? messages.subList(0, messages.size() - shortMemoryMessages.size())
-                : List.of();
-        String memorySummary = historyMessages.size() >= AiDefaults.MEMORY_SUMMARY_TRIGGER_MESSAGES
-                ? buildMemorySummary(historyMessages)
-                : null;
-        String memoryFacts = buildMemoryFacts(messages);
-        AiChatMessage lastMessage = aiChatMessageMapper.selectOne(new LambdaQueryWrapper<AiChatMessage>()
-                .eq(AiChatMessage::getSessionId, sessionId)
-                .eq(AiChatMessage::getDeleted, 0)
-                .orderByDesc(AiChatMessage::getSeqNo)
-                .orderByDesc(AiChatMessage::getId)
-                .last("limit 1"));
-        aiChatSessionMapper.updateById(new AiChatSession()
-                .setId(sessionId)
-                .setMemorySummary(memorySummary)
-                .setMemoryFacts(memoryFacts)
-                .setLastMessageTime(lastMessage == null ? null : lastMessage.getCreateTime())
-                .setUpdateBy(userId)
-                .setUpdateTime(new Date()));
-    }
-
-    private List<AiChatMessageDto> tailMessagesByRounds(List<AiChatMessageDto> source, int rounds) {
-        if (Cools.isEmpty(source) || rounds <= 0) {
-            return List.of();
-        }
-        int userCount = 0;
-        int startIndex = source.size();
-        for (int i = source.size() - 1; i >= 0; i--) {
-            AiChatMessageDto item = source.get(i);
-            startIndex = i;
-            if (item != null && "user".equalsIgnoreCase(item.getRole())) {
-                userCount++;
-                if (userCount >= rounds) {
-                    break;
-                }
-            }
-        }
-        return new ArrayList<>(source.subList(Math.max(0, startIndex), source.size()));
-    }
-
-    private List<AiChatMessage> tailMessageRecordsByRounds(List<AiChatMessage> source, int rounds) {
-        if (Cools.isEmpty(source) || rounds <= 0) {
-            return List.of();
-        }
-        int userCount = 0;
-        int startIndex = source.size();
-        for (int i = source.size() - 1; i >= 0; i--) {
-            AiChatMessage item = source.get(i);
-            startIndex = i;
-            if (item != null && "user".equalsIgnoreCase(item.getRole())) {
-                userCount++;
-                if (userCount >= rounds) {
-                    break;
-                }
-            }
-        }
-        return new ArrayList<>(source.subList(Math.max(0, startIndex), source.size()));
-    }
-
-    private String buildMemorySummary(List<AiChatMessageDto> historyMessages) {
-        StringBuilder builder = new StringBuilder("杈冩棭瀵硅瘽鎽樿:\n");
-        for (AiChatMessageDto item : historyMessages) {
-            if (item == null || !StringUtils.hasText(item.getContent())) {
-                continue;
-            }
-            String prefix = "assistant".equalsIgnoreCase(item.getRole()) ? "- AI: " : "- 鐢ㄦ埛: ";
-            String content = compactText(item.getContent(), 120);
-            if (!StringUtils.hasText(content)) {
-                continue;
-            }
-            builder.append(prefix).append(content).append("\n");
-            if (builder.length() >= AiDefaults.MEMORY_SUMMARY_MAX_LENGTH) {
-                break;
-            }
-        }
-        return compactText(builder.toString(), AiDefaults.MEMORY_SUMMARY_MAX_LENGTH);
-    }
-
-    private String buildMemoryFacts(List<AiChatMessageDto> messages) {
-        if (Cools.isEmpty(messages)) {
-            return null;
-        }
-        StringBuilder builder = new StringBuilder("鍏抽敭浜嬪疄:\n");
-        int userFacts = 0;
-        for (int i = messages.size() - 1; i >= 0 && userFacts < 4; i--) {
-            AiChatMessageDto item = messages.get(i);
-            if (item == null || !"user".equalsIgnoreCase(item.getRole()) || !StringUtils.hasText(item.getContent())) {
-                continue;
-            }
-            builder.append("- 鐢ㄦ埛鍏虫敞: ").append(compactText(item.getContent(), 100)).append("\n");
-            userFacts++;
-        }
-        return userFacts == 0 ? null : compactText(builder.toString(), AiDefaults.MEMORY_FACTS_MAX_LENGTH);
-    }
-
-    private String compactText(String content, int maxLength) {
-        if (!StringUtils.hasText(content)) {
-            return null;
-        }
-        String normalized = content.trim()
-                .replace("\r", " ")
-                .replace("\n", " ")
-                .replaceAll("\\s+", " ");
-        return normalized.length() > maxLength ? normalized.substring(0, maxLength) : normalized;
-    }
-
-    private void ensureIdentity(Long userId, Long tenantId) {
-        if (userId == null) {
-            throw new CoolException("褰撳墠鐧诲綍鐢ㄦ埛涓嶅瓨鍦�");
-        }
-        if (tenantId == null) {
-            throw new CoolException("褰撳墠绉熸埛涓嶅瓨鍦�");
-        }
-    }
-
-    private String requirePromptCode(String promptCode) {
-        if (!StringUtils.hasText(promptCode)) {
-            throw new CoolException("Prompt 缂栫爜涓嶈兘涓虹┖");
-        }
-        return promptCode;
+        aiConversationCommandService.retainLatestRound(userId, tenantId, sessionId);
     }
 }

--
Gitblit v1.9.1