import { DyNTS_Ass_Main_ControlService } from './ass-main.control-service'; import { DyNTS_Bot_Main_ControlService } from '../../bot/_services/bot-main.control-service'; import { DyNTS_AI_LLMChat_ServiceBase } from '../../ai/_services/ai-llm-chat.service-base'; import { DyNTS_Bot_MessageWrapper } from '../../bot/_models/bot-message-wrapper.interface'; import { DyNTS_Bot_ChannelWrapper } from '../../bot/_models/bot-channel-wrapper.interface'; import { DyFM_AI_Message } from '@futdevpro/fsm-dynamo/ai'; import { DyFM_Msg_Provider_Type } from '@futdevpro/fsm-dynamo/messaging'; import { DyNTS_Ass_Util } from '../_collections/ass.util'; import { DyNTS_Ass_global_settings } from '../_collections/ass-global-settings.const'; class TestAssMainService extends DyNTS_Ass_Main_ControlService { protected getAIProvider(): DyNTS_AI_LLMChat_ServiceBase { return { defaultSettings: { systemPrompt: 'Test prompt', useModel: 'test-model', }, } as any; } protected getBotIOControlService(): any { return {} as any; } protected getRoutinesControlService(): any { return {} as any; } protected getCommandsControlService(): any { return {} as any; } protected defaultProviderType: DyFM_Msg_Provider_Type = DyFM_Msg_Provider_Type.discord; protected availableProviders: any[] = []; static getInstance(): TestAssMainService { return TestAssMainService.getSingletonInstance(); } } describe('| DyNTS_Ass_Main_ControlService', () => { let service: TestAssMainService; beforeEach(() => { service = TestAssMainService.getInstance(); }); it('| should be a singleton instance', () => { const instance1 = TestAssMainService.getInstance(); const instance2 = TestAssMainService.getInstance(); expect(instance1).toBe(instance2); expect(instance1).toBeInstanceOf(TestAssMainService); }); it('| should have default system prompt', () => { expect(service.defaultSystemPrompt).toBe(DyNTS_Ass_global_settings.defaultSystemPrompt); }); it('| should initialize AI provider in constructor', () => { expect(service.aiProvider).toBeDefined(); }); describe('| gatherMessagesForMessage', () => { it('| should gather and filter messages', async () => { const mockMessage = { provider: { fetchMessagesForMessage: jasmine.createSpy('fetchMessagesForMessage').and.returnValue( Promise.resolve([ { content: 'Message 1', timestamp: 1000 }, { content: '[NOISE] Message 2', timestamp: 2000 }, { content: 'Message 3', timestamp: 3000 }, ] as any[]) ), }, } as any as DyNTS_Bot_MessageWrapper; const result = await service.gatherMessagesForMessage(mockMessage); expect(result.length).toBe(2); expect(result[0].content).toBe('Message 1'); expect(result[1].content).toBe('Message 3'); expect(mockMessage.provider.fetchMessagesForMessage).toHaveBeenCalledWith(mockMessage, 100); }); it('| should use custom limit', async () => { const mockMessage = { provider: { fetchMessagesForMessage: jasmine.createSpy('fetchMessagesForMessage').and.returnValue( Promise.resolve([]) ), }, } as any as DyNTS_Bot_MessageWrapper; await service.gatherMessagesForMessage(mockMessage, 50); expect(mockMessage.provider.fetchMessagesForMessage).toHaveBeenCalledWith(mockMessage, 50); }); it('| should sort messages by timestamp', async () => { const mockMessage = { provider: { fetchMessagesForMessage: jasmine.createSpy('fetchMessagesForMessage').and.returnValue( Promise.resolve([ { content: 'Message 3', timestamp: 3000 }, { content: 'Message 1', timestamp: 1000 }, { content: 'Message 2', timestamp: 2000 }, ] as any[]) ), }, } as any as DyNTS_Bot_MessageWrapper; const result = await service.gatherMessagesForMessage(mockMessage); expect(result[0].timestamp).toBe(1000); expect(result[1].timestamp).toBe(2000); expect(result[2].timestamp).toBe(3000); }); }); describe('| gatherMessagesInChannel', () => { it('| should gather messages from channel', async () => { const mockChannel = { provider: { fetchMessages: jasmine.createSpy('fetchMessages').and.returnValue( Promise.resolve([ { content: 'Message 1' }, { content: 'Message 2' }, ] as any[]) ), }, } as any as DyNTS_Bot_ChannelWrapper; const result = await service.gatherMessagesInChannel(mockChannel, 'issuer-123'); expect(result.length).toBe(2); expect(mockChannel.provider.fetchMessages).toHaveBeenCalledWith(mockChannel, 100); }); }); describe('| gatherMessagesAsAIConversation', () => { it('| should convert messages to AI conversation format', async () => { const mockMessage = { provider: { botId: 'bot-123', botDisplayName: 'Bot', fetchMessagesForMessage: jasmine.createSpy('fetchMessagesForMessage').and.returnValue( Promise.resolve([ { content: 'User message', authorId: 'user-123', isBot: false }, { content: 'Bot message', authorId: 'bot-123', isBot: true }, ] as any[]) ), }, } as any as DyNTS_Bot_MessageWrapper; spyOn(DyNTS_Ass_Util, 'convertBotMessagesToAIConversation').and.returnValue([ { role: 'user' as any, content: 'User message' }, { role: 'assistant' as any, content: 'Bot message' }, ]); const result = await service.gatherMessagesAsAIConversation(mockMessage, 'issuer-123'); expect(result.length).toBe(2); expect(DyNTS_Ass_Util.convertBotMessagesToAIConversation).toHaveBeenCalled(); }); }); describe('| gatherMessagesAsAIConversationInChannel', () => { it('| should convert channel messages to AI conversation format', async () => { const mockChannel = { provider: { botId: 'bot-123', botDisplayName: 'Bot', fetchMessages: jasmine.createSpy('fetchMessages').and.returnValue( Promise.resolve([ { content: 'User message', authorId: 'user-123', isBot: false }, ] as any[]) ), }, } as any as DyNTS_Bot_ChannelWrapper; spyOn(DyNTS_Ass_Util, 'convertBotMessagesToAIConversation').and.returnValue([ { role: 'user' as any, content: 'User message' }, ]); const result = await service.gatherMessagesAsAIConversationInChannel(mockChannel, 'issuer-123'); expect(result.length).toBe(1); expect(DyNTS_Ass_Util.convertBotMessagesToAIConversation).toHaveBeenCalled(); }); }); });