refactor(storage): 统一消息存储到 Core 层
问题:Server 端只存储最终文本响应,工具调用的中间消息丢失。 解决方案: - Agent.chat() 返回 ChatResult,包含完整消息链 - Server SessionManager 简化为只管理会话元数据 - 消息 API 改为从 Core Storage 读取 - 移除 Server 端的消息存储和 addMessage 方法 影响范围: - core: Agent.chat() 返回类型变更 - server: SessionManager 接口变更,移除消息存储 - server: GET /sessions/:id/messages 从 Core 读取 - server: 移除 POST /sessions/:id/messages 端点
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
* WebSocket Handler 测试
|
||||
*
|
||||
* 测试 WebSocket 连接处理、消息路由、广播功能等
|
||||
*
|
||||
* 注意:消息存储已移至 Core 层,Server 的 WebSocket 只负责消息广播和路由
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
@@ -9,7 +11,6 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
// Create mock functions
|
||||
const mockExists = vi.fn();
|
||||
const mockUpdateStatus = vi.fn();
|
||||
const mockAddMessage = vi.fn();
|
||||
const mockGet = vi.fn();
|
||||
|
||||
// Mock dependencies before imports
|
||||
@@ -17,7 +18,6 @@ vi.mock('../../src/session/manager.js', () => ({
|
||||
getSessionManager: vi.fn(() => ({
|
||||
exists: mockExists,
|
||||
updateStatus: mockUpdateStatus,
|
||||
addMessage: mockAddMessage,
|
||||
get: mockGet,
|
||||
})),
|
||||
}));
|
||||
@@ -60,7 +60,6 @@ describe('WebSocket Handler', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockExists.mockReturnValue(false);
|
||||
mockAddMessage.mockReturnValue({ id: 'msg-1', role: 'user', content: '', timestamp: Date.now() });
|
||||
});
|
||||
|
||||
describe('handleWebSocket - 连接处理', () => {
|
||||
@@ -110,6 +109,8 @@ describe('WebSocket Handler', () => {
|
||||
|
||||
it('处理 message 类型消息', async () => {
|
||||
const ws = createMockWSContext();
|
||||
handleWebSocket(ws as any, 'session-1');
|
||||
|
||||
const message = JSON.stringify({
|
||||
type: 'message',
|
||||
payload: { content: 'Hello AI' },
|
||||
@@ -117,10 +118,11 @@ describe('WebSocket Handler', () => {
|
||||
|
||||
await handleWebSocketMessage(ws as any, 'session-1', message);
|
||||
|
||||
expect(mockAddMessage).toHaveBeenCalledWith('session-1', {
|
||||
role: 'user',
|
||||
content: 'Hello AI',
|
||||
});
|
||||
// 应该广播 message_received 确认
|
||||
expect(ws.send).toHaveBeenCalledWith(
|
||||
expect.stringContaining('"type":"message_received"')
|
||||
);
|
||||
// 应该调用 processMessage
|
||||
expect(processMessage).toHaveBeenCalledWith('session-1', 'Hello AI');
|
||||
});
|
||||
|
||||
@@ -175,6 +177,7 @@ describe('WebSocket Handler', () => {
|
||||
|
||||
it('处理 ArrayBuffer 数据', async () => {
|
||||
const ws = createMockWSContext();
|
||||
handleWebSocket(ws as any, 'session-1');
|
||||
|
||||
const message = { type: 'message', payload: { content: 'ArrayBuffer test' } };
|
||||
const encoder = new TextEncoder();
|
||||
@@ -182,14 +185,13 @@ describe('WebSocket Handler', () => {
|
||||
|
||||
await handleWebSocketMessage(ws as any, 'session-1', buffer);
|
||||
|
||||
expect(mockAddMessage).toHaveBeenCalledWith('session-1', {
|
||||
role: 'user',
|
||||
content: 'ArrayBuffer test',
|
||||
});
|
||||
expect(processMessage).toHaveBeenCalledWith('session-1', 'ArrayBuffer test');
|
||||
});
|
||||
|
||||
it('空 content 处理正确', async () => {
|
||||
const ws = createMockWSContext();
|
||||
handleWebSocket(ws as any, 'session-1');
|
||||
|
||||
const message = JSON.stringify({
|
||||
type: 'message',
|
||||
payload: {},
|
||||
@@ -197,24 +199,19 @@ describe('WebSocket Handler', () => {
|
||||
|
||||
await handleWebSocketMessage(ws as any, 'session-1', message);
|
||||
|
||||
expect(mockAddMessage).toHaveBeenCalledWith('session-1', {
|
||||
role: 'user',
|
||||
content: '',
|
||||
});
|
||||
expect(processMessage).toHaveBeenCalledWith('session-1', '');
|
||||
});
|
||||
|
||||
it('处理 Blob 数据', async () => {
|
||||
const ws = createMockWSContext();
|
||||
handleWebSocket(ws as any, 'session-1');
|
||||
|
||||
const message = { type: 'message', payload: { content: 'Blob test' } };
|
||||
const blob = new Blob([JSON.stringify(message)]);
|
||||
|
||||
await handleWebSocketMessage(ws as any, 'session-1', blob);
|
||||
|
||||
expect(mockAddMessage).toHaveBeenCalledWith('session-1', {
|
||||
role: 'user',
|
||||
content: 'Blob test',
|
||||
});
|
||||
expect(processMessage).toHaveBeenCalledWith('session-1', 'Blob test');
|
||||
});
|
||||
|
||||
it('处理非标准数据类型(转为字符串)', async () => {
|
||||
@@ -229,21 +226,6 @@ describe('WebSocket Handler', () => {
|
||||
expect(cancelProcessing).toHaveBeenCalledWith('session-1');
|
||||
});
|
||||
|
||||
it('addMessage 返回 null 时不调用 processMessage', async () => {
|
||||
const ws = createMockWSContext();
|
||||
mockAddMessage.mockReturnValue(null);
|
||||
|
||||
const message = JSON.stringify({
|
||||
type: 'message',
|
||||
payload: { content: 'Test' },
|
||||
});
|
||||
|
||||
await handleWebSocketMessage(ws as any, 'session-1', message);
|
||||
|
||||
expect(mockAddMessage).toHaveBeenCalled();
|
||||
expect(processMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('处理 tool_response 类型消息(TODO 场景)', async () => {
|
||||
const ws = createMockWSContext();
|
||||
const message = JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user