diff --git a/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/methods/__tests__/loadModels.test.ts b/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/methods/__tests__/loadModels.test.ts index b2f728678f1..1e1e77fdae4 100644 --- a/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/methods/__tests__/loadModels.test.ts +++ b/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/methods/__tests__/loadModels.test.ts @@ -94,9 +94,9 @@ describe('searchModels', () => { const result = await searchModels.call(mockContext, 'gpt'); expect(result.results).toEqual([ - { name: 'gpt-4', value: 'gpt-4' }, - { name: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' }, { name: 'ft:gpt-3.5-turbo', value: 'ft:gpt-3.5-turbo' }, + { name: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' }, + { name: 'gpt-4', value: 'gpt-4' }, ]); }); @@ -104,9 +104,43 @@ describe('searchModels', () => { const result = await searchModels.call(mockContext, 'GPT'); expect(result.results).toEqual([ - { name: 'gpt-4', value: 'gpt-4' }, - { name: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' }, { name: 'ft:gpt-3.5-turbo', value: 'ft:gpt-3.5-turbo' }, + { name: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' }, + { name: 'gpt-4', value: 'gpt-4' }, + ]); + }); + + it('should return models sorted alphabetically by id', async () => { + // Setup a mock with scrambled order + const mockUnsortedInstance = { + apiKey: 'test-api-key', + models: { + list: jest.fn().mockResolvedValue({ + data: [ + { id: 'gpt-4' }, + { id: 'a-model' }, + { id: 'o1-model' }, + { id: 'gpt-3.5-turbo' }, + { id: 'z-model' }, + ], + }), + }, + } as unknown as OpenAI; + + (OpenAI as jest.MockedClass).mockImplementation(() => mockUnsortedInstance); + + // Custom API endpoint to include all models + mockContext.getNodeParameter = jest.fn().mockReturnValue('https://custom-api.com'); + + const result = await searchModels.call(mockContext); + + // Verify the results are sorted alphabetically + expect(result.results).toEqual([ + { name: 'a-model', value: 'a-model' }, + { name: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' }, + { name: 'gpt-4', value: 'gpt-4' }, + { name: 'o1-model', value: 'o1-model' }, + { name: 'z-model', value: 'z-model' }, ]); }); }); diff --git a/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/methods/loadModels.ts b/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/methods/loadModels.ts index bfcbfe1c30c..0badcfb6827 100644 --- a/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/methods/loadModels.ts +++ b/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/methods/loadModels.ts @@ -27,6 +27,8 @@ export async function searchModels( return isValidModel && model.id.toLowerCase().includes(filter.toLowerCase()); }); + filteredModels.sort((a, b) => a.id.localeCompare(b.id)); + const results = { results: filteredModels.map((model: { id: string }) => ({ name: model.id,