mirror of https://github.com/buster-so/buster.git
151 lines
4.4 KiB
TypeScript
151 lines
4.4 KiB
TypeScript
import type { CoreMessage } from 'ai';
|
|
import { afterAll, afterEach, describe, expect, test, vi } from 'vitest';
|
|
import { formatLlmMessagesAsReasoning } from '../../../src/utils/database/format-llm-messages-as-reasoning';
|
|
|
|
describe('formatLlmMessagesAsReasoning error handling', () => {
|
|
// Mock console.error to verify error logging
|
|
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
|
|
afterEach(() => {
|
|
consoleErrorSpy.mockClear();
|
|
});
|
|
|
|
afterAll(() => {
|
|
consoleErrorSpy.mockRestore();
|
|
});
|
|
|
|
test('handles non-array input gracefully', () => {
|
|
const result = formatLlmMessagesAsReasoning(null as never);
|
|
|
|
expect(result).toEqual([]);
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
'formatLlmMessagesAsReasoning: Expected array of messages, got:',
|
|
'object'
|
|
);
|
|
});
|
|
|
|
test('handles undefined input gracefully', () => {
|
|
const result = formatLlmMessagesAsReasoning(undefined as never);
|
|
|
|
expect(result).toEqual([]);
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
'formatLlmMessagesAsReasoning: Expected array of messages, got:',
|
|
'undefined'
|
|
);
|
|
});
|
|
|
|
test('skips null messages in array', () => {
|
|
const messages = [
|
|
null,
|
|
{
|
|
role: 'user',
|
|
content: 'Test message',
|
|
},
|
|
undefined,
|
|
] as never;
|
|
|
|
const result = formatLlmMessagesAsReasoning(messages);
|
|
|
|
expect(result).toHaveLength(1); // Only the valid message is processed
|
|
expect(result[0]).toHaveProperty('type', 'text');
|
|
expect(result[0]).toHaveProperty('message', 'Test message');
|
|
expect(consoleErrorSpy).toHaveBeenCalledTimes(2); // For null and undefined
|
|
});
|
|
|
|
test('handles tool calls with missing args gracefully', () => {
|
|
const messages: CoreMessage[] = [
|
|
{
|
|
role: 'assistant',
|
|
content: [
|
|
{
|
|
type: 'tool-call',
|
|
toolCallId: 'test-id',
|
|
toolName: 'unknownTool', // Use unknown tool to test default case
|
|
args: undefined as never, // Missing args
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const result = formatLlmMessagesAsReasoning(messages);
|
|
|
|
// Should still create a reasoning message with default handling
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toHaveProperty('title', 'unknownTool');
|
|
expect(result[0]).toHaveProperty('message', '{}'); // Empty object stringified
|
|
});
|
|
|
|
test('handles circular references in tool args', () => {
|
|
const circularObj: { a: number; self?: unknown } = { a: 1 };
|
|
circularObj.self = circularObj; // Create circular reference
|
|
|
|
const messages: CoreMessage[] = [
|
|
{
|
|
role: 'assistant',
|
|
content: [
|
|
{
|
|
type: 'tool-call',
|
|
toolCallId: 'test-id',
|
|
toolName: 'unknownTool',
|
|
args: circularObj,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const result = formatLlmMessagesAsReasoning(messages);
|
|
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toHaveProperty('message', '[Unable to display tool arguments]');
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
'Failed to stringify args for tool unknownTool:',
|
|
expect.any(Error)
|
|
);
|
|
});
|
|
|
|
test('continues processing after encountering an error', () => {
|
|
const messages: CoreMessage[] = [
|
|
{
|
|
role: 'assistant',
|
|
content: [
|
|
{
|
|
type: 'tool-call',
|
|
toolCallId: 'fail-id',
|
|
toolName: 'sequentialThinking',
|
|
args: undefined as never, // This will be skipped because no thought
|
|
},
|
|
],
|
|
},
|
|
{
|
|
role: 'user',
|
|
content: 'Valid message after error',
|
|
},
|
|
];
|
|
|
|
const result = formatLlmMessagesAsReasoning(messages);
|
|
|
|
// First message is skipped because sequentialThinking without args.thought returns null
|
|
// Only the user message is processed
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toHaveProperty('message', 'Valid message after error');
|
|
});
|
|
|
|
test('handles messages with complex content arrays', () => {
|
|
const messages: CoreMessage[] = [
|
|
{
|
|
role: 'assistant',
|
|
content: [
|
|
{ type: 'text', text: 'Hello' },
|
|
{ type: 'image', image: 'data:image/png;base64,...' } as never,
|
|
{ type: 'text', text: 'World' },
|
|
],
|
|
},
|
|
];
|
|
|
|
const result = formatLlmMessagesAsReasoning(messages);
|
|
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toHaveProperty('message', 'Hello [image] World');
|
|
});
|
|
});
|