UNPKG

n8n

Version:

n8n Workflow Automation Tool

663 lines 28.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChatHubModelsService = void 0; const api_types_1 = require("@n8n/api-types"); const db_1 = require("@n8n/db"); const di_1 = require("@n8n/di"); const n8n_workflow_1 = require("n8n-workflow"); const credentials_finder_service_1 = require("../../credentials/credentials-finder.service"); const dynamic_node_parameters_service_1 = require("../../services/dynamic-node-parameters.service"); const workflow_execute_additional_data_1 = require("../../workflow-execute-additional-data"); const workflow_service_1 = require("../../workflows/workflow.service"); const chat_hub_agent_service_1 = require("./chat-hub-agent.service"); const chat_hub_workflow_service_1 = require("./chat-hub-workflow.service"); const chat_hub_constants_1 = require("./chat-hub.constants"); const chat_hub_types_1 = require("./chat-hub.types"); let ChatHubModelsService = class ChatHubModelsService { constructor(nodeParametersService, workflowService, workflowRepository, credentialsFinderService, chatHubAgentService, chatHubWorkflowService) { this.nodeParametersService = nodeParametersService; this.workflowService = workflowService; this.workflowRepository = workflowRepository; this.credentialsFinderService = credentialsFinderService; this.chatHubAgentService = chatHubAgentService; this.chatHubWorkflowService = chatHubWorkflowService; } async getModels(user, credentialIds) { const additionalData = await (0, workflow_execute_additional_data_1.getBase)({ userId: user.id }); const providers = api_types_1.chatHubProviderSchema.options; const allCredentials = await this.credentialsFinderService.findCredentialsForUser(user, [ 'credential:read', ]); const responses = await Promise.all(providers.map(async (provider) => { const credentials = {}; if (provider !== 'n8n' && provider !== 'custom-agent') { const credentialId = credentialIds[provider]; if (!credentialId) { return [provider, { models: [] }]; } if (!allCredentials.some((credential) => credential.id === credentialId)) { return [ provider, { models: [], error: 'Could not retrieve models. Verify credentials.' }, ]; } credentials[api_types_1.PROVIDER_CREDENTIAL_TYPE_MAP[provider]] = { name: '', id: credentialId }; } try { return [ provider, await this.fetchModelsForProvider(user, provider, credentials, additionalData), ]; } catch { return [ provider, { models: [], error: 'Could not retrieve models. Verify credentials.' }, ]; } })); return responses.reduce((acc, [provider, res]) => { acc[provider] = res; return acc; }, { ...api_types_1.emptyChatModelsResponse }); } async fetchModelsForProvider(user, provider, credentials, additionalData) { switch (provider) { case 'openai': { const rawModels = await this.fetchOpenAiModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'openai') }; } case 'anthropic': { const rawModels = await this.fetchAnthropicModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'anthropic') }; } case 'google': { const rawModels = await this.fetchGoogleModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'google') }; } case 'ollama': { const rawModels = await this.fetchOllamaModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'ollama') }; } case 'azureOpenAi': { const rawModels = this.fetchAzureOpenAiModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'azureOpenAi') }; } case 'azureEntraId': { const rawModels = this.fetchAzureEntraIdModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'azureEntraId') }; } case 'awsBedrock': { const rawModels = await this.fetchAwsBedrockModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'awsBedrock') }; } case 'vercelAiGateway': { const rawModels = await this.fetchVercelAiGatewayModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'vercelAiGateway') }; } case 'xAiGrok': { const rawModels = await this.fetchXAiGrokModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'xAiGrok') }; } case 'groq': { const rawModels = await this.fetchGroqModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'groq') }; } case 'openRouter': { const rawModels = await this.fetchOpenRouterModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'openRouter') }; } case 'deepSeek': { const rawModels = await this.fetchDeepSeekModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'deepSeek') }; } case 'cohere': { const rawModels = await this.fetchCohereModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'cohere') }; } case 'mistralCloud': { const rawModels = await this.fetchMistralCloudModels(credentials, additionalData); return { models: this.transformAndFilterModels(rawModels, 'mistralCloud') }; } case 'n8n': return { models: await this.fetchAgentWorkflowsAsModels(user) }; case 'custom-agent': return { models: await this.chatHubAgentService.getAgentsByUserIdAsModels(user.id) }; } } async fetchOpenAiModels(credentials, additionalData) { const resourceLocatorResults = await this.nodeParametersService.getResourceLocatorResults('searchModels', 'parameters.model', additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.openai, {}, credentials); return resourceLocatorResults.results; } async fetchAnthropicModels(credentials, additionalData) { const resourceLocatorResults = await this.nodeParametersService.getResourceLocatorResults('searchModels', 'parameters.model', additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.anthropic, {}, credentials); return resourceLocatorResults.results; } async fetchGoogleModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/v1beta/models', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'models', }, }, { type: 'filter', properties: { pass: "={{ !$responseItem.name.includes('embedding') }}", }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.name}}', value: '={{$responseItem.name}}', description: '={{$responseItem.description}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.google, {}, credentials); } async fetchOllamaModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/api/tags', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'models', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.name}}', value: '={{$responseItem.name}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.ollama, {}, credentials); } fetchAzureOpenAiModels(_credentials, _additionalData) { return []; } fetchAzureEntraIdModels(_credentials, _additionalData) { return []; } async fetchAwsBedrockModels(credentials, additionalData) { const foundationModelsRequest = this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/foundation-models?&byOutputModality=TEXT&byInferenceType=ON_DEMAND', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'modelSummaries', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.modelName}}', description: '={{$responseItem.modelArn}}', value: '={{$responseItem.modelId}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.awsBedrock, {}, credentials); const inferenceProfileModelsRequest = this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/inference-profiles?maxResults=1000', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'inferenceProfileSummaries', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.inferenceProfileName}}', description: '={{$responseItem.description || $responseItem.inferenceProfileArn}}', value: '={{$responseItem.inferenceProfileId}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.awsBedrock, {}, credentials); const [foundationModels, inferenceProfileModels] = await Promise.all([ foundationModelsRequest, inferenceProfileModelsRequest, ]); return foundationModels.concat(inferenceProfileModels); } async fetchMistralCloudModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/models', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'data', }, }, { type: 'filter', properties: { pass: "={{ !$responseItem.id.includes('embed') }}", }, }, { type: 'setKeyValue', properties: { name: '={{ $responseItem.id }}', value: '={{ $responseItem.id }}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.mistralCloud, {}, credentials); } async fetchCohereModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/v1/models?page_size=100&endpoint=chat', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'models', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.name}}', value: '={{$responseItem.name}}', description: '={{$responseItem.description}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.cohere, {}, credentials); } async fetchDeepSeekModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/models', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'data', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.id}}', value: '={{$responseItem.id}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.deepSeek, {}, credentials); } async fetchOpenRouterModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/models', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'data', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.id}}', value: '={{$responseItem.id}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.openRouter, {}, credentials); } async fetchGroqModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/models', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'data', }, }, { type: 'filter', properties: { pass: '={{ $responseItem.active === true && $responseItem.object === "model" }}', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.id}}', value: '={{$responseItem.id}}', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.groq, {}, credentials); } async fetchXAiGrokModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/models', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'data', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.id}}', value: '={{$responseItem.id}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.xAiGrok, {}, credentials); } async fetchVercelAiGatewayModels(credentials, additionalData) { return await this.nodeParametersService.getOptionsViaLoadOptions({ routing: { request: { method: 'GET', url: '/models', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'data', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.id}}', value: '={{$responseItem.id}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, additionalData, chat_hub_constants_1.PROVIDER_NODE_TYPE_MAP.vercelAiGateway, {}, credentials); } async fetchAgentWorkflowsAsModels(user) { const workflowsWithChatTrigger = await this.workflowService.getWorkflowsWithNodesIncluded(user, [n8n_workflow_1.CHAT_TRIGGER_NODE_TYPE], true); const activeWorkflows = workflowsWithChatTrigger .filter((workflow) => workflow.scopes.includes('workflow:execute-chat')) .filter((workflow) => !!workflow.activeVersionId); if (activeWorkflows.length === 0) { return []; } const workflows = await this.workflowRepository.find({ select: { id: true, name: true, shared: { role: true, project: { id: true, name: true, type: true, icon: { type: true, value: true }, }, }, }, where: { id: (0, db_1.In)(activeWorkflows.map((workflow) => workflow.id)) }, relations: { activeVersion: true, shared: { project: true, }, }, }); return workflows.flatMap((workflow) => { const scopes = activeWorkflows.find((w) => w.id === workflow.id)?.scopes ?? []; const model = this.extractModelFromWorkflow(workflow, scopes); return model ? [model] : []; }); } extractModelFromWorkflow({ name, activeVersion, id, shared }, scopes) { if (!activeVersion) { return null; } const chatTrigger = activeVersion.nodes?.find((node) => node.type === n8n_workflow_1.CHAT_TRIGGER_NODE_TYPE); if (!chatTrigger) { return null; } const chatTriggerParams = chat_hub_types_1.chatTriggerParamsShape.safeParse(chatTrigger.parameters).data; if (!chatTriggerParams?.availableInChat) { return null; } const { allowFileUploads, allowedFilesMimeTypes } = this.chatHubWorkflowService.resolveWorkflowAttachmentPolicy(activeVersion.nodes ?? []); const agentName = chatTriggerParams.agentName && chatTriggerParams.agentName.trim().length > 0 ? chatTriggerParams.agentName : name; const suggestedPrompts = this.parseSuggestedPrompts(chatTriggerParams.suggestedPrompts); const { groupName, groupIcon } = this.resolveOwnerProject(shared); return { name: agentName, description: chatTriggerParams.agentDescription ?? null, icon: chatTriggerParams.agentIcon ?? null, model: { provider: 'n8n', workflowId: id, }, createdAt: activeVersion.createdAt ? activeVersion.createdAt.toISOString() : null, updatedAt: activeVersion.updatedAt ? activeVersion.updatedAt.toISOString() : null, metadata: { allowFileUploads, allowedFilesMimeTypes, capabilities: { functionCalling: false, }, available: true, scopes, }, groupName, groupIcon, ...(suggestedPrompts.length > 0 ? { suggestedPrompts } : {}), }; } parseSuggestedPrompts(raw) { return (raw?.prompts ?.filter((p) => p.text.trim().length > 0) .map((p) => ({ text: p.text, ...(p.icon ? { icon: p.icon } : {}) })) ?? []); } resolveOwnerProject(shared) { const ownerProject = shared?.find((sw) => sw.role === 'workflow:owner')?.project; return { groupName: ownerProject?.type === 'personal' ? null : (ownerProject?.name ?? null), groupIcon: ownerProject?.icon ?? null, }; } transformAndFilterModels(rawModels, provider) { const seen = new Set(); return rawModels.flatMap((model) => { const id = String(model.value); const metadata = (0, chat_hub_constants_1.getModelMetadata)(provider, id); if (!metadata.available) return []; if (seen.has(id)) return []; seen.add(id); return [ { id, name: model.name, description: model.description ?? null, icon: null, model: { provider, model: id, }, createdAt: null, updatedAt: null, metadata, groupName: null, groupIcon: null, }, ]; }); } }; exports.ChatHubModelsService = ChatHubModelsService; exports.ChatHubModelsService = ChatHubModelsService = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [dynamic_node_parameters_service_1.DynamicNodeParametersService, workflow_service_1.WorkflowService, db_1.WorkflowRepository, credentials_finder_service_1.CredentialsFinderService, chat_hub_agent_service_1.ChatHubAgentService, chat_hub_workflow_service_1.ChatHubWorkflowService]) ], ChatHubModelsService); //# sourceMappingURL=chat-hub.models.service.js.map