buster/packages/test-utils/tests/database-tests/messages/conversationHistory.test.ts

264 lines
7.4 KiB
TypeScript

import { cleanupTestEnvironment, setupTestEnvironment } from '@buster/test-utils';
import { createTestChat, createTestMessage } from '@buster/test-utils';
import type { CoreMessage } from 'ai';
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
import { getChatConversationHistory } from '../../../src/helpers/messages/chatConversationHistory';
describe('Conversation History Loading', () => {
beforeEach(async () => {
await setupTestEnvironment();
});
afterEach(async () => {
await cleanupTestEnvironment();
});
test('should load conversation history in proper unbundled format', async () => {
const { chatId, userId } = await createTestChat();
// Create messages with proper unbundled structure
const properConversationHistory: CoreMessage[] = [
{
role: 'user',
content: 'What are our top 5 products by revenue?',
},
{
role: 'assistant',
content: [
{
type: 'tool-call',
toolName: 'sequentialThinking',
toolCallId: 'tool-1',
args: { thought: 'Analyzing request...' },
},
],
},
{
role: 'tool',
content: [
{
type: 'tool-result',
result: { success: true },
toolName: 'sequentialThinking',
toolCallId: 'tool-1',
},
],
},
{
role: 'assistant',
content: [
{
type: 'tool-call',
toolName: 'submitThoughts',
toolCallId: 'tool-2',
args: {},
},
],
},
{
role: 'tool',
content: [
{
type: 'tool-result',
result: {},
toolName: 'submitThoughts',
toolCallId: 'tool-2',
},
],
},
];
// Create a message with this conversation history
const messageId = await createTestMessage(chatId, userId, {
rawLlmMessages: properConversationHistory,
requestMessage: 'What are our top 5 products by revenue?',
});
// Load the conversation history
const loadedHistory = await getChatConversationHistory({ messageId });
// Verify the structure is preserved
expect(loadedHistory).toHaveLength(5);
expect(loadedHistory[0].role).toBe('user');
expect(loadedHistory[1].role).toBe('assistant');
expect(loadedHistory[2].role).toBe('tool');
expect(loadedHistory[3].role).toBe('assistant');
expect(loadedHistory[4].role).toBe('tool');
// Verify tool calls are properly structured
const firstAssistantMsg = loadedHistory[1];
expect(firstAssistantMsg.content).toBeInstanceOf(Array);
expect(firstAssistantMsg.content[0]).toHaveProperty('type', 'tool-call');
expect(firstAssistantMsg.content[0]).toHaveProperty('toolName', 'sequentialThinking');
// Verify tool results are properly structured
const firstToolMsg = loadedHistory[2];
expect(firstToolMsg.content).toBeInstanceOf(Array);
expect(firstToolMsg.content[0]).toHaveProperty('type', 'tool-result');
expect(firstToolMsg.content[0]).toHaveProperty('toolName', 'sequentialThinking');
});
test('should combine multiple messages from a chat while preserving order', async () => {
const { chatId, userId } = await createTestChat();
// First interaction
const firstHistory: CoreMessage[] = [
{
role: 'user',
content: 'First question',
},
{
role: 'assistant',
content: [
{
type: 'tool-call',
toolName: 'analyzeData',
toolCallId: 'tool-1',
args: {},
},
],
},
{
role: 'tool',
content: [
{
type: 'tool-result',
result: { data: 'result1' },
toolName: 'analyzeData',
toolCallId: 'tool-1',
},
],
},
];
// Second interaction
const secondHistory: CoreMessage[] = [
{
role: 'user',
content: 'Follow-up question',
},
{
role: 'assistant',
content: [
{
type: 'tool-call',
toolName: 'generateChart',
toolCallId: 'tool-2',
args: {},
},
],
},
{
role: 'tool',
content: [
{
type: 'tool-result',
result: { chart: 'data' },
toolName: 'generateChart',
toolCallId: 'tool-2',
},
],
},
];
// Create two messages in the same chat
await createTestMessage(chatId, userId, {
rawLlmMessages: firstHistory,
requestMessage: 'First question',
});
const secondMessageId = await createTestMessage(chatId, userId, {
rawLlmMessages: secondHistory,
requestMessage: 'Follow-up question',
});
// Load conversation history from the second message
const fullHistory = await getChatConversationHistory({ messageId: secondMessageId });
// Should have all 6 messages in order
expect(fullHistory).toHaveLength(6);
// Verify the correct pattern
expect(fullHistory[0].role).toBe('user');
expect(fullHistory[0].content).toBe('First question');
expect(fullHistory[1].role).toBe('assistant');
expect(fullHistory[2].role).toBe('tool');
expect(fullHistory[3].role).toBe('user');
expect(fullHistory[3].content).toBe('Follow-up question');
expect(fullHistory[4].role).toBe('assistant');
expect(fullHistory[5].role).toBe('tool');
// Verify tools are correct
expect(fullHistory[1].content[0].toolName).toBe('analyzeData');
expect(fullHistory[4].content[0].toolName).toBe('generateChart');
});
test('should handle empty conversation history', async () => {
const { chatId, userId } = await createTestChat();
const messageId = await createTestMessage(chatId, userId, {
rawLlmMessages: [],
requestMessage: 'Test message',
});
const history = await getChatConversationHistory({ messageId });
expect(history).toEqual([]);
});
test('should maintain exact message structure without modification', async () => {
const { chatId, userId } = await createTestChat();
const complexHistory: CoreMessage[] = [
{
role: 'user',
content: 'Complex request',
},
{
role: 'assistant',
content: [
{
type: 'tool-call',
toolName: 'complexTool',
toolCallId: 'complex-1',
args: {
nested: {
data: {
values: [1, 2, 3],
config: { mode: 'advanced' },
},
},
},
},
],
},
{
role: 'tool',
content: [
{
type: 'tool-result',
result: {
complex: {
output: {
data: 'processed',
metadata: { timestamp: '2024-01-01' },
},
},
},
toolName: 'complexTool',
toolCallId: 'complex-1',
},
],
},
];
const messageId = await createTestMessage(chatId, userId, {
rawLlmMessages: complexHistory,
});
const loaded = await getChatConversationHistory({ messageId });
// Deep equality check - structure should be exactly preserved
expect(loaded).toEqual(complexHistory);
});
});