132 lines
3.8 KiB
TypeScript
132 lines
3.8 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import type { ChatMessageSchema } from '@insforge/shared-schemas';
|
|
|
|
// Mock dependencies before importing the service
|
|
vi.mock('../../src/providers/ai/openrouter.provider.js', () => ({
|
|
OpenRouterProvider: { getInstance: () => ({}) },
|
|
}));
|
|
vi.mock('../../src/utils/logger.js', () => ({
|
|
default: { error: vi.fn(), info: vi.fn(), warn: vi.fn() },
|
|
}));
|
|
|
|
describe('ChatCompletionService - formatMessages', () => {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
let service: any;
|
|
|
|
beforeEach(async () => {
|
|
const mod = await import('../../src/services/ai/chat-completion.service.js');
|
|
service = mod.ChatCompletionService.getInstance();
|
|
});
|
|
|
|
it('formats tool role messages with tool_call_id', () => {
|
|
const messages: ChatMessageSchema[] = [
|
|
{
|
|
role: 'tool',
|
|
content: '{"temp":"22°C"}',
|
|
tool_call_id: 'call_abc123',
|
|
},
|
|
];
|
|
|
|
const result = service.formatMessages(messages);
|
|
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toEqual({
|
|
role: 'tool',
|
|
content: '{"temp":"22°C"}',
|
|
tool_call_id: 'call_abc123',
|
|
});
|
|
});
|
|
|
|
it('formats assistant messages with tool_calls', () => {
|
|
const messages: ChatMessageSchema[] = [
|
|
{
|
|
role: 'assistant',
|
|
content: null,
|
|
tool_calls: [
|
|
{
|
|
id: 'call_abc123',
|
|
type: 'function',
|
|
function: { name: 'get_weather', arguments: '{"city":"Tokyo"}' },
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const result = service.formatMessages(messages);
|
|
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].role).toBe('assistant');
|
|
expect(result[0].content).toBeNull();
|
|
expect(result[0].tool_calls).toEqual([
|
|
{
|
|
id: 'call_abc123',
|
|
type: 'function',
|
|
function: { name: 'get_weather', arguments: '{"city":"Tokyo"}' },
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('formats regular user messages unchanged', () => {
|
|
const messages: ChatMessageSchema[] = [{ role: 'user', content: 'Hello' }];
|
|
|
|
const result = service.formatMessages(messages);
|
|
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toEqual({ role: 'user', content: 'Hello' });
|
|
});
|
|
|
|
it('prepends system prompt when provided', () => {
|
|
const messages: ChatMessageSchema[] = [{ role: 'user', content: 'Hi' }];
|
|
|
|
const result = service.formatMessages(messages, 'You are helpful.');
|
|
|
|
expect(result).toHaveLength(2);
|
|
expect(result[0]).toEqual({ role: 'system', content: 'You are helpful.' });
|
|
expect(result[1]).toEqual({ role: 'user', content: 'Hi' });
|
|
});
|
|
|
|
it('handles a full multi-turn tool calling conversation', () => {
|
|
const messages: ChatMessageSchema[] = [
|
|
{ role: 'user', content: 'What is the weather in Tokyo?' },
|
|
{
|
|
role: 'assistant',
|
|
content: null,
|
|
tool_calls: [
|
|
{
|
|
id: 'call_1',
|
|
type: 'function',
|
|
function: { name: 'get_weather', arguments: '{"city":"Tokyo"}' },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
role: 'tool',
|
|
content: '{"temp":"22°C","condition":"sunny"}',
|
|
tool_call_id: 'call_1',
|
|
},
|
|
];
|
|
|
|
const result = service.formatMessages(messages);
|
|
|
|
expect(result).toHaveLength(3);
|
|
expect(result[0].role).toBe('user');
|
|
expect(result[1].role).toBe('assistant');
|
|
expect(result[1].tool_calls).toBeDefined();
|
|
expect(result[2].role).toBe('tool');
|
|
expect(result[2].tool_call_id).toBe('call_1');
|
|
});
|
|
|
|
it('throws on tool message with empty tool_call_id', () => {
|
|
const messages: ChatMessageSchema[] = [
|
|
{
|
|
role: 'tool',
|
|
content: 'result',
|
|
},
|
|
];
|
|
|
|
expect(() => service.formatMessages(messages)).toThrow(
|
|
'Tool message is missing required tool_call_id'
|
|
);
|
|
});
|
|
});
|