feat: 全新智能体功能
- 基于先进智能体框架,增加智能体编排功能 - 增加智能体聊天,并对接持久化
This commit is contained in:
@@ -16,12 +16,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.*;
|
||||
|
||||
@Repository
|
||||
public class MySqlChatSessionRepository {
|
||||
@@ -110,6 +105,10 @@ public class MySqlChatSessionRepository {
|
||||
}
|
||||
|
||||
public List<ChatSessionSummary> listSessions(BigInteger userId, BigInteger assistantId, ChatPageQuery query) {
|
||||
return listSessions(userId, assistantId, null, query);
|
||||
}
|
||||
|
||||
public List<ChatSessionSummary> listSessions(BigInteger userId, BigInteger assistantId, String assistantCode, ChatPageQuery query) {
|
||||
String table = tableRouter.resolveSessionTable();
|
||||
List<Object> params = new ArrayList<>();
|
||||
StringBuilder sql = new StringBuilder("SELECT * FROM `").append(table)
|
||||
@@ -119,6 +118,10 @@ public class MySqlChatSessionRepository {
|
||||
sql.append(" AND assistant_id=?");
|
||||
params.add(assistantId);
|
||||
}
|
||||
if (assistantCode != null && !assistantCode.isBlank()) {
|
||||
sql.append(" AND assistant_code=?");
|
||||
params.add(assistantCode);
|
||||
}
|
||||
sql.append(" ORDER BY last_message_at DESC, id DESC LIMIT ? OFFSET ?");
|
||||
params.add(query.getPageSize());
|
||||
params.add(query.getOffset());
|
||||
@@ -126,6 +129,10 @@ public class MySqlChatSessionRepository {
|
||||
}
|
||||
|
||||
public long countSessions(BigInteger userId, BigInteger assistantId) {
|
||||
return countSessions(userId, assistantId, null);
|
||||
}
|
||||
|
||||
public long countSessions(BigInteger userId, BigInteger assistantId, String assistantCode) {
|
||||
String table = tableRouter.resolveSessionTable();
|
||||
List<Object> params = new ArrayList<>();
|
||||
StringBuilder sql = new StringBuilder("SELECT COUNT(1) FROM `").append(table)
|
||||
@@ -135,6 +142,10 @@ public class MySqlChatSessionRepository {
|
||||
sql.append(" AND assistant_id=?");
|
||||
params.add(assistantId);
|
||||
}
|
||||
if (assistantCode != null && !assistantCode.isBlank()) {
|
||||
sql.append(" AND assistant_code=?");
|
||||
params.add(assistantCode);
|
||||
}
|
||||
Long count = jdbcTemplate.queryForObject(sql.toString(), Long.class, params.toArray());
|
||||
return count == null ? 0L : count;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package tech.easyflow.chatlog.service;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.stereotype.Service;
|
||||
import tech.easyflow.chatlog.cache.ChatHotStateService;
|
||||
import tech.easyflow.chatlog.domain.command.ChatAppendMessageCommand;
|
||||
@@ -107,7 +107,7 @@ public class ChatPersistDispatcher {
|
||||
payload.setTitle(title);
|
||||
payload.setOperatorId(operatorId);
|
||||
payload.setOperateAt(operateAt);
|
||||
eventProducer.send(buildEvent(
|
||||
ChatPersistEvent event = buildEvent(
|
||||
UUID.randomUUID().toString(),
|
||||
ChatPersistEventType.SESSION_RENAMED,
|
||||
sessionId,
|
||||
@@ -115,7 +115,9 @@ public class ChatPersistDispatcher {
|
||||
BigInteger.ZERO,
|
||||
operateAt,
|
||||
chatJsonSupport.toJson(payload)
|
||||
));
|
||||
);
|
||||
persistImmediately(event);
|
||||
eventProducer.send(event);
|
||||
}
|
||||
|
||||
public void deleteSession(BigInteger sessionId, BigInteger userId, BigInteger operatorId) {
|
||||
|
||||
@@ -2,13 +2,8 @@ package tech.easyflow.chatlog.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import tech.easyflow.chatlog.domain.command.ChatAppendMessageCommand;
|
||||
import tech.easyflow.chatlog.domain.command.ChatRoundSelectCommand;
|
||||
import tech.easyflow.chatlog.domain.command.ChatRoundUpsertCommand;
|
||||
import tech.easyflow.chatlog.domain.command.ChatSessionSummaryCommand;
|
||||
import tech.easyflow.chatlog.domain.command.ChatSessionUpsertCommand;
|
||||
import tech.easyflow.chatlog.domain.command.*;
|
||||
import tech.easyflow.chatlog.domain.event.ChatPersistEvent;
|
||||
import tech.easyflow.chatlog.domain.event.ChatPersistEventType;
|
||||
import tech.easyflow.chatlog.domain.event.payload.ChatSessionDeletePayload;
|
||||
import tech.easyflow.chatlog.domain.event.payload.ChatSessionRenamePayload;
|
||||
import tech.easyflow.chatlog.repository.mysql.MySqlChatLogRepository;
|
||||
@@ -21,13 +16,7 @@ import tech.easyflow.chatlog.support.ChatJsonSupport;
|
||||
import java.math.BigInteger;
|
||||
import java.time.YearMonth;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class ChatPersistMySqlApplyService {
|
||||
@@ -231,9 +220,6 @@ public class ChatPersistMySqlApplyService {
|
||||
if (isBlank(upsert.getUserAccount())) {
|
||||
upsert.setUserAccount("");
|
||||
}
|
||||
if (isBlank(upsert.getTitle())) {
|
||||
upsert.setTitle("会话-" + upsert.getSessionId());
|
||||
}
|
||||
if (upsert.getOperateAt() == null) {
|
||||
upsert.setOperateAt(new Date());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package tech.easyflow.chatlog.service;
|
||||
|
||||
import tech.easyflow.chatlog.domain.dto.ChatMessageRecord;
|
||||
import tech.easyflow.chatlog.domain.dto.ChatHistoryPage;
|
||||
import tech.easyflow.chatlog.domain.dto.ChatMessageRecord;
|
||||
import tech.easyflow.chatlog.domain.dto.ChatSessionPage;
|
||||
import tech.easyflow.chatlog.domain.dto.ChatSessionSummary;
|
||||
import tech.easyflow.chatlog.domain.query.ChatPageQuery;
|
||||
@@ -13,10 +13,57 @@ public interface ChatSessionQueryService {
|
||||
|
||||
List<ChatSessionSummary> listSessions(BigInteger userId, BigInteger assistantId, ChatPageQuery query);
|
||||
|
||||
/**
|
||||
* 按助手编码查询用户会话列表。
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @param assistantId 助手 ID,可为空
|
||||
* @param assistantCode 助手编码,可为空
|
||||
* @param query 分页参数
|
||||
* @return 会话列表
|
||||
*/
|
||||
default List<ChatSessionSummary> listSessions(BigInteger userId, BigInteger assistantId, String assistantCode, ChatPageQuery query) {
|
||||
if (assistantCode != null && !assistantCode.isBlank()) {
|
||||
throw new UnsupportedOperationException("当前会话查询实现不支持 assistantCode 过滤");
|
||||
}
|
||||
return listSessions(userId, assistantId, query);
|
||||
}
|
||||
|
||||
long countSessions(BigInteger userId, BigInteger assistantId);
|
||||
|
||||
/**
|
||||
* 按助手编码统计用户会话数。
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @param assistantId 助手 ID,可为空
|
||||
* @param assistantCode 助手编码,可为空
|
||||
* @return 会话数
|
||||
*/
|
||||
default long countSessions(BigInteger userId, BigInteger assistantId, String assistantCode) {
|
||||
if (assistantCode != null && !assistantCode.isBlank()) {
|
||||
throw new UnsupportedOperationException("当前会话查询实现不支持 assistantCode 过滤");
|
||||
}
|
||||
return countSessions(userId, assistantId);
|
||||
}
|
||||
|
||||
ChatSessionPage pageSessions(BigInteger userId, BigInteger assistantId, ChatPageQuery query);
|
||||
|
||||
/**
|
||||
* 按助手编码分页查询用户会话。
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @param assistantId 助手 ID,可为空
|
||||
* @param assistantCode 助手编码,可为空
|
||||
* @param query 分页参数
|
||||
* @return 会话分页
|
||||
*/
|
||||
default ChatSessionPage pageSessions(BigInteger userId, BigInteger assistantId, String assistantCode, ChatPageQuery query) {
|
||||
if (assistantCode != null && !assistantCode.isBlank()) {
|
||||
throw new UnsupportedOperationException("当前会话查询实现不支持 assistantCode 过滤");
|
||||
}
|
||||
return pageSessions(userId, assistantId, query);
|
||||
}
|
||||
|
||||
ChatSessionSummary getSessionSummary(BigInteger sessionId);
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,12 +13,7 @@ import tech.easyflow.chatlog.repository.mysql.MySqlChatSessionRepository;
|
||||
import tech.easyflow.chatlog.service.ChatSessionQueryService;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class ChatSessionQueryServiceImpl implements ChatSessionQueryService {
|
||||
@@ -40,22 +35,37 @@ public class ChatSessionQueryServiceImpl implements ChatSessionQueryService {
|
||||
|
||||
@Override
|
||||
public List<ChatSessionSummary> listSessions(BigInteger userId, BigInteger assistantId, ChatPageQuery query) {
|
||||
return sessionRepository.listSessions(userId, assistantId, query);
|
||||
return listSessions(userId, assistantId, null, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChatSessionSummary> listSessions(BigInteger userId, BigInteger assistantId, String assistantCode, ChatPageQuery query) {
|
||||
return sessionRepository.listSessions(userId, assistantId, assistantCode, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countSessions(BigInteger userId, BigInteger assistantId) {
|
||||
return sessionRepository.countSessions(userId, assistantId);
|
||||
return countSessions(userId, assistantId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countSessions(BigInteger userId, BigInteger assistantId, String assistantCode) {
|
||||
return sessionRepository.countSessions(userId, assistantId, assistantCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatSessionPage pageSessions(BigInteger userId, BigInteger assistantId, ChatPageQuery query) {
|
||||
return pageSessions(userId, assistantId, null, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatSessionPage pageSessions(BigInteger userId, BigInteger assistantId, String assistantCode, ChatPageQuery query) {
|
||||
ChatSessionPage page = new ChatSessionPage();
|
||||
page.setPageNumber(query.getPageNumber());
|
||||
page.setPageSize(query.getPageSize());
|
||||
|
||||
page.setTotal(sessionRepository.countSessions(userId, assistantId));
|
||||
page.setRecords(listSessions(userId, assistantId, query));
|
||||
page.setTotal(sessionRepository.countSessions(userId, assistantId, assistantCode));
|
||||
page.setRecords(listSessions(userId, assistantId, assistantCode, query));
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class ChatPersistMySqlApplyServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFallbackTitleWhenMessageMetadataMissing() {
|
||||
public void shouldKeepTitleBlankWhenMessageMetadataMissing() {
|
||||
ChatAppendMessageCommand command = new ChatAppendMessageCommand();
|
||||
command.setSessionId(BigInteger.valueOf(202));
|
||||
command.setTenantId(BigInteger.ONE);
|
||||
@@ -77,7 +77,7 @@ public class ChatPersistMySqlApplyServiceTest {
|
||||
Assert.assertEquals(1, upserts.size());
|
||||
ChatSessionUpsertCommand upsert = upserts.get(0);
|
||||
Assert.assertEquals("", upsert.getUserAccount());
|
||||
Assert.assertEquals("会话-202", upsert.getTitle());
|
||||
Assert.assertNull(upsert.getTitle());
|
||||
Assert.assertEquals(BigInteger.valueOf(7), upsert.getOperatorId());
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,27 @@ public class ChatSessionQueryServiceImplTest {
|
||||
Assert.assertEquals(1, sessionRepository.listSessionsCalls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Agent 会话查询必须把 assistantCode 过滤条件下推到 MySQL 会话表,避免混入 Bot 会话。
|
||||
*/
|
||||
@Test
|
||||
public void pageSessionsShouldPassAssistantCodeFilterToMysqlRepository() {
|
||||
FakeSessionRepository sessionRepository = new FakeSessionRepository();
|
||||
sessionRepository.sessions = List.of(session(BigInteger.valueOf(1002), 2));
|
||||
sessionRepository.count = 1;
|
||||
ChatSessionQueryServiceImpl service = new ChatSessionQueryServiceImpl(
|
||||
sessionRepository,
|
||||
new FakeLogRepository(),
|
||||
new FakeTableManager(List.of()),
|
||||
new FakeHotStateService()
|
||||
);
|
||||
|
||||
service.pageSessions(BigInteger.valueOf(7), BigInteger.valueOf(88), "AGENT", new ChatPageQuery());
|
||||
|
||||
Assert.assertEquals("AGENT", sessionRepository.capturedListAssistantCode);
|
||||
Assert.assertEquals("AGENT", sessionRepository.capturedCountAssistantCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 工作台消息分页必须走 MySQL 热表主线查询,并保持分页参数语义。
|
||||
*/
|
||||
@@ -124,6 +145,8 @@ public class ChatSessionQueryServiceImplTest {
|
||||
private long count;
|
||||
private int countSessionsCalls;
|
||||
private int listSessionsCalls;
|
||||
private String capturedListAssistantCode;
|
||||
private String capturedCountAssistantCode;
|
||||
private ChatSessionSummary summary;
|
||||
private List<ChatSessionSummary> sessions = new ArrayList<>();
|
||||
|
||||
@@ -133,13 +156,25 @@ public class ChatSessionQueryServiceImplTest {
|
||||
|
||||
@Override
|
||||
public List<ChatSessionSummary> listSessions(BigInteger userId, BigInteger assistantId, ChatPageQuery query) {
|
||||
return listSessions(userId, assistantId, null, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChatSessionSummary> listSessions(BigInteger userId, BigInteger assistantId, String assistantCode, ChatPageQuery query) {
|
||||
listSessionsCalls += 1;
|
||||
capturedListAssistantCode = assistantCode;
|
||||
return sessions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countSessions(BigInteger userId, BigInteger assistantId) {
|
||||
return countSessions(userId, assistantId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countSessions(BigInteger userId, BigInteger assistantId, String assistantCode) {
|
||||
countSessionsCalls += 1;
|
||||
capturedCountAssistantCode = assistantCode;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user