mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
139 lines
4.2 KiB
TypeScript
139 lines
4.2 KiB
TypeScript
import type { ComputedRef, MaybeRef } from 'vue';
|
|
import { ref, computed, unref } from 'vue';
|
|
import {
|
|
CHAIN_SUMMARIZATION_LANGCHAIN_NODE_TYPE,
|
|
NodeConnectionType,
|
|
NodeHelpers,
|
|
} from 'n8n-workflow';
|
|
import type { INodeTypeDescription, Workflow, INode, INodeParameters } from 'n8n-workflow';
|
|
import {
|
|
AI_CATEGORY_AGENTS,
|
|
AI_CATEGORY_CHAINS,
|
|
AI_CODE_NODE_TYPE,
|
|
AI_SUBCATEGORY,
|
|
CHAT_TRIGGER_NODE_TYPE,
|
|
MANUAL_CHAT_TRIGGER_NODE_TYPE,
|
|
} from '@/constants';
|
|
import type { INodeUi } from '@/Interface';
|
|
|
|
export interface ChatTriggerDependencies {
|
|
getNodeByName: (name: string) => INodeUi | null;
|
|
getNodeType: (type: string, version: number) => INodeTypeDescription | null;
|
|
canvasNodes: MaybeRef<INodeUi[]>;
|
|
workflow: ComputedRef<Workflow>;
|
|
}
|
|
|
|
export function useChatTrigger({
|
|
getNodeByName,
|
|
getNodeType,
|
|
canvasNodes,
|
|
workflow,
|
|
}: ChatTriggerDependencies) {
|
|
const chatTriggerName = ref<string | null>(null);
|
|
const connectedNode = ref<INode | null>(null);
|
|
|
|
const chatTriggerNode = computed(() =>
|
|
chatTriggerName.value ? getNodeByName(chatTriggerName.value) : null,
|
|
);
|
|
|
|
const allowFileUploads = computed(() => {
|
|
return (
|
|
(chatTriggerNode.value?.parameters?.options as INodeParameters)?.allowFileUploads === true
|
|
);
|
|
});
|
|
|
|
const allowedFilesMimeTypes = computed(() => {
|
|
return (
|
|
(
|
|
chatTriggerNode.value?.parameters?.options as INodeParameters
|
|
)?.allowedFilesMimeTypes?.toString() ?? ''
|
|
);
|
|
});
|
|
|
|
/** Gets the chat trigger node from the workflow */
|
|
function setChatTriggerNode() {
|
|
const triggerNode = unref(canvasNodes).find((node) =>
|
|
[CHAT_TRIGGER_NODE_TYPE, MANUAL_CHAT_TRIGGER_NODE_TYPE].includes(node.type),
|
|
);
|
|
|
|
if (!triggerNode) {
|
|
return;
|
|
}
|
|
chatTriggerName.value = triggerNode.name;
|
|
}
|
|
|
|
/** Sets the connected node after finding the trigger */
|
|
function setConnectedNode() {
|
|
const triggerNode = chatTriggerNode.value;
|
|
|
|
if (!triggerNode) {
|
|
return;
|
|
}
|
|
|
|
const chatChildren = workflow.value.getChildNodes(triggerNode.name);
|
|
|
|
const chatRootNode = chatChildren
|
|
.reverse()
|
|
.map((nodeName: string) => getNodeByName(nodeName))
|
|
.filter((n): n is INodeUi => n !== null)
|
|
// Reverse the nodes to match the last node logs first
|
|
.reverse()
|
|
.find((storeNode: INodeUi): boolean => {
|
|
// Skip summarization nodes
|
|
if (storeNode.type === CHAIN_SUMMARIZATION_LANGCHAIN_NODE_TYPE) return false;
|
|
const nodeType = getNodeType(storeNode.type, storeNode.typeVersion);
|
|
|
|
if (!nodeType) return false;
|
|
|
|
// Check if node is an AI agent or chain based on its metadata
|
|
const isAgent =
|
|
nodeType.codex?.subcategories?.[AI_SUBCATEGORY]?.includes(AI_CATEGORY_AGENTS);
|
|
const isChain =
|
|
nodeType.codex?.subcategories?.[AI_SUBCATEGORY]?.includes(AI_CATEGORY_CHAINS);
|
|
|
|
// Handle custom AI Langchain Code nodes that could act as chains or agents
|
|
let isCustomChainOrAgent = false;
|
|
if (nodeType.name === AI_CODE_NODE_TYPE) {
|
|
// Get node connection types for inputs and outputs
|
|
const inputs = NodeHelpers.getNodeInputs(workflow.value, storeNode, nodeType);
|
|
const inputTypes = NodeHelpers.getConnectionTypes(inputs);
|
|
|
|
const outputs = NodeHelpers.getNodeOutputs(workflow.value, storeNode, nodeType);
|
|
const outputTypes = NodeHelpers.getConnectionTypes(outputs);
|
|
|
|
// Validate if node has required AI connection types
|
|
if (
|
|
inputTypes.includes(NodeConnectionType.AiLanguageModel) &&
|
|
inputTypes.includes(NodeConnectionType.Main) &&
|
|
outputTypes.includes(NodeConnectionType.Main)
|
|
) {
|
|
isCustomChainOrAgent = true;
|
|
}
|
|
}
|
|
|
|
// Skip if node is not an AI component
|
|
if (!isAgent && !isChain && !isCustomChainOrAgent) return false;
|
|
|
|
// Check if this node is connected to the trigger node
|
|
const parentNodes = workflow.value.getParentNodes(storeNode.name);
|
|
const isChatChild = parentNodes.some(
|
|
(parentNodeName) => parentNodeName === triggerNode.name,
|
|
);
|
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
const result = Boolean(isChatChild && (isAgent || isChain || isCustomChainOrAgent));
|
|
return result;
|
|
});
|
|
connectedNode.value = chatRootNode ?? null;
|
|
}
|
|
|
|
return {
|
|
allowFileUploads,
|
|
allowedFilesMimeTypes,
|
|
chatTriggerNode,
|
|
connectedNode: computed(() => connectedNode.value),
|
|
setChatTriggerNode,
|
|
setConnectedNode,
|
|
};
|
|
}
|