Commit 78976885fd5b86de869db65c7a1acba8ec59376d

Authored by YunaiV
1 parent edffc819

fix(ai1): 对齐消息页顺序并兼容 JDK 17

yudao-module-ai1-springai/src/main/java/cn/iocoder/yudao/module/ai1/controller/admin/session/Ai1SessionMessageController.java
@@ -77,7 +77,7 @@ public class Ai1SessionMessageController { @@ -77,7 +77,7 @@ public class Ai1SessionMessageController {
77 // ==================== 管理 ==================== 77 // ==================== 管理 ====================
78 78
79 @GetMapping("/page") 79 @GetMapping("/page")
80 - @Operation(summary = "获得会话消息分页", description = "按消息编号倒序") 80 + @Operation(summary = "获得会话消息分页", description = "按消息编号倒序取最新页,页内按时间正序")
81 @PreAuthorize("@ss.hasPermission('ai1:session:query')") 81 @PreAuthorize("@ss.hasPermission('ai1:session:query')")
82 public CommonResult<PageResult<Ai1SessionMessageRespVO>> getSessionMessagePage(@Valid Ai1SessionMessagePageReqVO pageReqVO) { 82 public CommonResult<PageResult<Ai1SessionMessageRespVO>> getSessionMessagePage(@Valid Ai1SessionMessagePageReqVO pageReqVO) {
83 return success(BeanUtils.toBean(sessionMessageService.getSessionMessagePage(pageReqVO), 83 return success(BeanUtils.toBean(sessionMessageService.getSessionMessagePage(pageReqVO),
yudao-module-ai1-springai/src/main/java/cn/iocoder/yudao/module/ai1/harness/session/Ai1SessionStreamTool.java
@@ -529,7 +529,7 @@ public class Ai1SessionStreamTool implements SmartLifecycle { @@ -529,7 +529,7 @@ public class Ai1SessionStreamTool implements SmartLifecycle {
529 if (!lock.tryLock()) { 529 if (!lock.tryLock()) {
530 return false; 530 return false;
531 } 531 }
532 - long ownerThreadId = Thread.currentThread().threadId(); 532 + long ownerThreadId = Thread.currentThread().getId();
533 try { 533 try {
534 // 3. 锁内重新读取,期间可能已被 worker 完成 534 // 3. 锁内重新读取,期间可能已被 worker 完成
535 Ai1SessionMessageDO current = sessionMessageService.getSessionMessage(messageId); 535 Ai1SessionMessageDO current = sessionMessageService.getSessionMessage(messageId);
@@ -687,7 +687,7 @@ public class Ai1SessionStreamTool implements SmartLifecycle { @@ -687,7 +687,7 @@ public class Ai1SessionStreamTool implements SmartLifecycle {
687 if (!lock.tryLock()) { 687 if (!lock.tryLock()) {
688 return; 688 return;
689 } 689 }
690 - long workerThreadId = Thread.currentThread().threadId(); 690 + long workerThreadId = Thread.currentThread().getId();
691 try { 691 try {
692 Long tenantId = Convert.toLong(fields.get(FIELD_TENANT_ID)); 692 Long tenantId = Convert.toLong(fields.get(FIELD_TENANT_ID));
693 TenantUtils.execute(tenantId, () -> executeTask(recordId, fields, messageId, lock, workerThreadId, reclaimed)); 693 TenantUtils.execute(tenantId, () -> executeTask(recordId, fields, messageId, lock, workerThreadId, reclaimed));
yudao-module-ai1-springai/src/main/java/cn/iocoder/yudao/module/ai1/service/session/Ai1SessionMessageService.java
@@ -26,7 +26,7 @@ public interface Ai1SessionMessageService { @@ -26,7 +26,7 @@ public interface Ai1SessionMessageService {
26 List<Ai1SessionMessageDO> getSessionMessageListBySessionId(Long sessionId); 26 List<Ai1SessionMessageDO> getSessionMessageListBySessionId(Long sessionId);
27 27
28 /** 28 /**
29 - * 获得会话消息分页,按编号倒序 29 + * 获得会话消息分页,按编号倒序取最新页,页内按时间正序
30 * 30 *
31 * @param pageReqVO 分页查询 31 * @param pageReqVO 分页查询
32 * @return 消息分页 32 * @return 消息分页
yudao-module-ai1-springai/src/main/java/cn/iocoder/yudao/module/ai1/service/session/Ai1SessionMessageServiceImpl.java
@@ -63,7 +63,12 @@ public class Ai1SessionMessageServiceImpl implements Ai1SessionMessageService { @@ -63,7 +63,12 @@ public class Ai1SessionMessageServiceImpl implements Ai1SessionMessageService {
63 63
64 @Override 64 @Override
65 public PageResult<Ai1SessionMessageDO> getSessionMessagePage(Ai1SessionMessagePageReqVO pageReqVO) { 65 public PageResult<Ai1SessionMessageDO> getSessionMessagePage(Ai1SessionMessagePageReqVO pageReqVO) {
66 - return sessionMessageMapper.selectPage(pageReqVO); 66 + PageResult<Ai1SessionMessageDO> pageResult = sessionMessageMapper.selectPage(pageReqVO);
  67 + // 按编号倒序取最新页,页内反转为时间正序
  68 + if (CollUtil.isNotEmpty(pageResult.getList())) {
  69 + Collections.reverse(pageResult.getList());
  70 + }
  71 + return pageResult;
67 } 72 }
68 73
69 @Override 74 @Override
yudao-module-ai1-springai/src/test/java/cn/iocoder/yudao/module/ai1/harness/mcp/Ai1McpToolFactoryTest.java
@@ -67,7 +67,7 @@ public class Ai1McpToolFactoryTest extends BaseMockitoUnitTest { @@ -67,7 +67,7 @@ public class Ai1McpToolFactoryTest extends BaseMockitoUnitTest {
67 // 调用 67 // 调用
68 List<ToolCallback> callbacks = buildTools(List.of(mcp), List.of("search")); 68 List<ToolCallback> callbacks = buildTools(List.of(mcp), List.of("search"));
69 // 断言 69 // 断言
70 - assertEquals("github__search", callbacks.getFirst().getToolDefinition().name()); 70 + assertEquals("github__search", callbacks.get(0).getToolDefinition().name());
71 } 71 }
72 72
73 @Test 73 @Test
@@ -78,8 +78,8 @@ public class Ai1McpToolFactoryTest extends BaseMockitoUnitTest { @@ -78,8 +78,8 @@ public class Ai1McpToolFactoryTest extends BaseMockitoUnitTest {
78 // 调用 78 // 调用
79 List<ToolCallback> callbacks = buildTools(List.of(mcp), List.of("search")); 79 List<ToolCallback> callbacks = buildTools(List.of(mcp), List.of("search"));
80 // 断言 80 // 断言
81 - assertEquals("a".repeat(56) + "__search", callbacks.getFirst().getToolDefinition().name());  
82 - assertEquals(64, callbacks.getFirst().getToolDefinition().name().length()); 81 + assertEquals("a".repeat(56) + "__search", callbacks.get(0).getToolDefinition().name());
  82 + assertEquals(64, callbacks.get(0).getToolDefinition().name().length());
83 } 83 }
84 84
85 @Test 85 @Test
@@ -127,7 +127,7 @@ public class Ai1McpToolFactoryTest extends BaseMockitoUnitTest { @@ -127,7 +127,7 @@ public class Ai1McpToolFactoryTest extends BaseMockitoUnitTest {
127 List<ToolCallback> callbacks = buildTools(List.of(mcp), List.of(toolName)); 127 List<ToolCallback> callbacks = buildTools(List.of(mcp), List.of(toolName));
128 128
129 // 调用 129 // 调用
130 - String result = callbacks.getFirst().call("{\"query\":\"北京\"}"); 130 + String result = callbacks.get(0).call("{\"query\":\"北京\"}");
131 // 断言 131 // 断言
132 assertEquals("搜索结果", JsonUtils.parseObject(result, String.class)); 132 assertEquals("搜索结果", JsonUtils.parseObject(result, String.class));
133 verify(mcpClientTool).callTool(mcp, toolName, arguments); 133 verify(mcpClientTool).callTool(mcp, toolName, arguments);
yudao-module-ai1-springai/src/test/java/cn/iocoder/yudao/module/ai1/service/session/Ai1SessionMessageServiceImplTest.java
@@ -171,11 +171,25 @@ public class Ai1SessionMessageServiceImplTest extends BaseDbUnitTest { @@ -171,11 +171,25 @@ public class Ai1SessionMessageServiceImplTest extends BaseDbUnitTest {
171 171
172 // 调用 172 // 调用
173 PageResult<Ai1SessionMessageDO> pageResult = sessionMessageService.getSessionMessagePage(reqVO); 173 PageResult<Ai1SessionMessageDO> pageResult = sessionMessageService.getSessionMessagePage(reqVO);
174 - // 断言:按编号倒序 174 + // 断言:取最新一页,页内按时间正序
175 assertEquals(3, pageResult.getTotal()); 175 assertEquals(3, pageResult.getTotal());
176 - assertEquals(List.of(message3.getId(), message2.getId()), 176 + assertEquals(List.of(message2.getId(), message3.getId()),
177 pageResult.getList().stream().map(Ai1SessionMessageDO::getId).toList()); 177 pageResult.getList().stream().map(Ai1SessionMessageDO::getId).toList());
178 - assertNotEquals(message1.getId(), pageResult.getList().get(1).getId()); 178 +
  179 + // 调用:第二页
  180 + reqVO.setPageNo(2);
  181 + pageResult = sessionMessageService.getSessionMessagePage(reqVO);
  182 + // 断言:更早的消息
  183 + assertEquals(3, pageResult.getTotal());
  184 + assertEquals(List.of(message1.getId()),
  185 + pageResult.getList().stream().map(Ai1SessionMessageDO::getId).toList());
  186 +
  187 + // 调用:超出范围的空页
  188 + reqVO.setPageNo(3);
  189 + pageResult = sessionMessageService.getSessionMessagePage(reqVO);
  190 + // 断言
  191 + assertEquals(3, pageResult.getTotal());
  192 + assertTrue(pageResult.getList().isEmpty());
179 } 193 }
180 194
181 @Test 195 @Test