mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
feat: Add more AI node info to telemetry (#8827)
This commit is contained in:
parent
0f7ae3f50a
commit
ed6dc86d60
|
@ -1083,6 +1083,7 @@ export default defineComponent({
|
||||||
TelemetryHelpers.generateNodesGraph(
|
TelemetryHelpers.generateNodesGraph(
|
||||||
workflowData as IWorkflowBase,
|
workflowData as IWorkflowBase,
|
||||||
this.workflowHelpers.getNodeTypes(),
|
this.workflowHelpers.getNodeTypes(),
|
||||||
|
{ isCloudDeployment: this.settingsStore.isCloudDeployment },
|
||||||
).nodeGraph,
|
).nodeGraph,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -1991,6 +1992,7 @@ export default defineComponent({
|
||||||
TelemetryHelpers.generateNodesGraph(
|
TelemetryHelpers.generateNodesGraph(
|
||||||
workflowData as IWorkflowBase,
|
workflowData as IWorkflowBase,
|
||||||
this.workflowHelpers.getNodeTypes(),
|
this.workflowHelpers.getNodeTypes(),
|
||||||
|
{ isCloudDeployment: this.settingsStore.isCloudDeployment },
|
||||||
).nodeGraph,
|
).nodeGraph,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -2147,6 +2149,7 @@ export default defineComponent({
|
||||||
workflowData.meta && workflowData.meta.instanceId !== currInstanceId
|
workflowData.meta && workflowData.meta.instanceId !== currInstanceId
|
||||||
? workflowData.meta.instanceId
|
? workflowData.meta.instanceId
|
||||||
: '',
|
: '',
|
||||||
|
isCloudDeployment: this.settingsStore.isCloudDeployment,
|
||||||
},
|
},
|
||||||
).nodeGraph,
|
).nodeGraph,
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,18 +6,54 @@ export const LOG_LEVELS = ['silent', 'error', 'warn', 'info', 'debug', 'verbose'
|
||||||
export const CODE_LANGUAGES = ['javaScript', 'python'] as const;
|
export const CODE_LANGUAGES = ['javaScript', 'python'] as const;
|
||||||
export const CODE_EXECUTION_MODES = ['runOnceForAllItems', 'runOnceForEachItem'] as const;
|
export const CODE_EXECUTION_MODES = ['runOnceForAllItems', 'runOnceForEachItem'] as const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Nodes whose parameter values may refer to other nodes without expressions.
|
|
||||||
* Their content may need to be updated when the referenced node is renamed.
|
|
||||||
*/
|
|
||||||
export const NODES_WITH_RENAMABLE_CONTENT = new Set([
|
|
||||||
'n8n-nodes-base.code',
|
|
||||||
'n8n-nodes-base.function',
|
|
||||||
'n8n-nodes-base.functionItem',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Arbitrary value to represent an empty credential value
|
// Arbitrary value to represent an empty credential value
|
||||||
export const CREDENTIAL_EMPTY_VALUE =
|
export const CREDENTIAL_EMPTY_VALUE =
|
||||||
'__n8n_EMPTY_VALUE_7b1af746-3729-4c60-9b9b-e08eb29e58da' as const;
|
'__n8n_EMPTY_VALUE_7b1af746-3729-4c60-9b9b-e08eb29e58da' as const;
|
||||||
|
|
||||||
export const FORM_TRIGGER_PATH_IDENTIFIER = 'n8n-form';
|
export const FORM_TRIGGER_PATH_IDENTIFIER = 'n8n-form';
|
||||||
|
|
||||||
|
//n8n-nodes-base
|
||||||
|
export const STICKY_NODE_TYPE = 'n8n-nodes-base.stickyNote';
|
||||||
|
export const NO_OP_NODE_TYPE = 'n8n-nodes-base.noOp';
|
||||||
|
export const HTTP_REQUEST_NODE_TYPE = 'n8n-nodes-base.httpRequest';
|
||||||
|
export const WEBHOOK_NODE_TYPE = 'n8n-nodes-base.webhook';
|
||||||
|
export const MANUAL_TRIGGER_NODE_TYPE = 'n8n-nodes-base.manualTrigger';
|
||||||
|
export const ERROR_TRIGGER_NODE_TYPE = 'n8n-nodes-base.errorTrigger';
|
||||||
|
export const START_NODE_TYPE = 'n8n-nodes-base.start';
|
||||||
|
export const EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE = 'n8n-nodes-base.executeWorkflowTrigger';
|
||||||
|
export const CODE_NODE_TYPE = 'n8n-nodes-base.code';
|
||||||
|
export const FUNCTION_NODE_TYPE = 'n8n-nodes-base.function';
|
||||||
|
export const FUNCTION_ITEM_NODE_TYPE = 'n8n-nodes-base.functionItem';
|
||||||
|
|
||||||
|
export const STARTING_NODE_TYPES = [
|
||||||
|
MANUAL_TRIGGER_NODE_TYPE,
|
||||||
|
EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||||
|
ERROR_TRIGGER_NODE_TYPE,
|
||||||
|
START_NODE_TYPE,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const SCRIPTING_NODE_TYPES = [FUNCTION_NODE_TYPE, FUNCTION_ITEM_NODE_TYPE, CODE_NODE_TYPE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nodes whose parameter values may refer to other nodes without expressions.
|
||||||
|
* Their content may need to be updated when the referenced node is renamed.
|
||||||
|
*/
|
||||||
|
export const NODES_WITH_RENAMABLE_CONTENT = new Set([
|
||||||
|
CODE_NODE_TYPE,
|
||||||
|
FUNCTION_NODE_TYPE,
|
||||||
|
FUNCTION_ITEM_NODE_TYPE,
|
||||||
|
]);
|
||||||
|
|
||||||
|
//@n8n/n8n-nodes-langchain
|
||||||
|
export const MANUAL_CHAT_TRIGGER_LANGCHAIN_NODE_TYPE = '@n8n/n8n-nodes-langchain.manualChatTrigger';
|
||||||
|
export const AGENT_LANGCHAIN_NODE_TYPE = '@n8n/n8n-nodes-langchain.agent';
|
||||||
|
export const OPENAI_LANGCHAIN_NODE_TYPE = '@n8n/n8n-nodes-langchain.openAi';
|
||||||
|
export const CHAIN_SUMMARIZATION_LANGCHAIN_NODE_TYPE =
|
||||||
|
'@n8n/n8n-nodes-langchain.chainSummarization';
|
||||||
|
export const CODE_TOOL_LANGCHAIN_NODE_TYPE = '@n8n/n8n-nodes-langchain.toolCode';
|
||||||
|
export const WORKFLOW_TOOL_LANGCHAIN_NODE_TYPE = '@n8n/n8n-nodes-langchain.toolWorkflow';
|
||||||
|
|
||||||
|
export const LANGCHAIN_CUSTOM_TOOLS = [
|
||||||
|
CODE_TOOL_LANGCHAIN_NODE_TYPE,
|
||||||
|
WORKFLOW_TOOL_LANGCHAIN_NODE_TYPE,
|
||||||
|
];
|
||||||
|
|
|
@ -2238,6 +2238,7 @@ export interface INodeGraphItem {
|
||||||
src_node_id?: string;
|
src_node_id?: string;
|
||||||
src_instance_id?: string;
|
src_instance_id?: string;
|
||||||
agent?: string; //@n8n/n8n-nodes-langchain.agent
|
agent?: string; //@n8n/n8n-nodes-langchain.agent
|
||||||
|
prompts?: IDataObject[] | IDataObject; //ai node's prompts, cloud only
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INodeNameIndex {
|
export interface INodeNameIndex {
|
||||||
|
|
|
@ -8,10 +8,18 @@ import type {
|
||||||
INodesGraphResult,
|
INodesGraphResult,
|
||||||
IWorkflowBase,
|
IWorkflowBase,
|
||||||
INodeTypes,
|
INodeTypes,
|
||||||
|
IDataObject,
|
||||||
} from './Interfaces';
|
} from './Interfaces';
|
||||||
import { ApplicationError } from './errors/application.error';
|
import { ApplicationError } from './errors/application.error';
|
||||||
|
import {
|
||||||
const STICKY_NODE_TYPE = 'n8n-nodes-base.stickyNote';
|
AGENT_LANGCHAIN_NODE_TYPE,
|
||||||
|
CHAIN_SUMMARIZATION_LANGCHAIN_NODE_TYPE,
|
||||||
|
HTTP_REQUEST_NODE_TYPE,
|
||||||
|
LANGCHAIN_CUSTOM_TOOLS,
|
||||||
|
OPENAI_LANGCHAIN_NODE_TYPE,
|
||||||
|
STICKY_NODE_TYPE,
|
||||||
|
WEBHOOK_NODE_TYPE,
|
||||||
|
} from './Constants';
|
||||||
|
|
||||||
export function getNodeTypeForName(workflow: IWorkflowBase, nodeName: string): INode | undefined {
|
export function getNodeTypeForName(workflow: IWorkflowBase, nodeName: string): INode | undefined {
|
||||||
return workflow.nodes.find((node) => node.name === nodeName);
|
return workflow.nodes.find((node) => node.name === nodeName);
|
||||||
|
@ -95,6 +103,7 @@ export function generateNodesGraph(
|
||||||
options?: {
|
options?: {
|
||||||
sourceInstanceId?: string;
|
sourceInstanceId?: string;
|
||||||
nodeIdMap?: { [curr: string]: string };
|
nodeIdMap?: { [curr: string]: string };
|
||||||
|
isCloudDeployment?: boolean;
|
||||||
},
|
},
|
||||||
): INodesGraphResult {
|
): INodesGraphResult {
|
||||||
const nodeGraph: INodesGraph = {
|
const nodeGraph: INodesGraph = {
|
||||||
|
@ -158,15 +167,15 @@ export function generateNodesGraph(
|
||||||
nodeItem.src_node_id = options.nodeIdMap[node.id];
|
nodeItem.src_node_id = options.nodeIdMap[node.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.type === '@n8n/n8n-nodes-langchain.agent') {
|
if (node.type === AGENT_LANGCHAIN_NODE_TYPE) {
|
||||||
nodeItem.agent = (node.parameters.agent as string) || 'conversationalAgent';
|
nodeItem.agent = (node.parameters.agent as string) || 'conversationalAgent';
|
||||||
} else if (node.type === 'n8n-nodes-base.httpRequest' && node.typeVersion === 1) {
|
} else if (node.type === HTTP_REQUEST_NODE_TYPE && node.typeVersion === 1) {
|
||||||
try {
|
try {
|
||||||
nodeItem.domain = new URL(node.parameters.url as string).hostname;
|
nodeItem.domain = new URL(node.parameters.url as string).hostname;
|
||||||
} catch {
|
} catch {
|
||||||
nodeItem.domain = getDomainBase(node.parameters.url as string);
|
nodeItem.domain = getDomainBase(node.parameters.url as string);
|
||||||
}
|
}
|
||||||
} else if (node.type === 'n8n-nodes-base.httpRequest' && node.typeVersion > 1) {
|
} else if (node.type === HTTP_REQUEST_NODE_TYPE && node.typeVersion > 1) {
|
||||||
const { authentication } = node.parameters as { authentication: string };
|
const { authentication } = node.parameters as { authentication: string };
|
||||||
|
|
||||||
nodeItem.credential_type = {
|
nodeItem.credential_type = {
|
||||||
|
@ -182,7 +191,7 @@ export function generateNodesGraph(
|
||||||
nodeItem.domain_base = getDomainBase(url);
|
nodeItem.domain_base = getDomainBase(url);
|
||||||
nodeItem.domain_path = getDomainPath(url);
|
nodeItem.domain_path = getDomainPath(url);
|
||||||
nodeItem.method = node.parameters.requestMethod as string;
|
nodeItem.method = node.parameters.requestMethod as string;
|
||||||
} else if (node.type === 'n8n-nodes-base.webhook') {
|
} else if (node.type === WEBHOOK_NODE_TYPE) {
|
||||||
webhookNodeNames.push(node.name);
|
webhookNodeNames.push(node.name);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
@ -216,6 +225,58 @@ export function generateNodesGraph(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options?.isCloudDeployment === true) {
|
||||||
|
if (node.type === OPENAI_LANGCHAIN_NODE_TYPE) {
|
||||||
|
nodeItem.prompts =
|
||||||
|
(((node.parameters?.messages as IDataObject) || {}).values as IDataObject[]) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.type === AGENT_LANGCHAIN_NODE_TYPE) {
|
||||||
|
const prompts: IDataObject = {};
|
||||||
|
|
||||||
|
if (node.parameters?.text) {
|
||||||
|
prompts.text = node.parameters.text as string;
|
||||||
|
}
|
||||||
|
const nodeOptions = node.parameters?.options as IDataObject;
|
||||||
|
|
||||||
|
if (nodeOptions) {
|
||||||
|
const optionalMessagesKeys = [
|
||||||
|
'humanMessage',
|
||||||
|
'systemMessage',
|
||||||
|
'humanMessageTemplate',
|
||||||
|
'prefix',
|
||||||
|
'suffixChat',
|
||||||
|
'suffix',
|
||||||
|
'prefixPrompt',
|
||||||
|
'suffixPrompt',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const key of optionalMessagesKeys) {
|
||||||
|
if (nodeOptions[key]) {
|
||||||
|
prompts[key] = nodeOptions[key] as string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(prompts).length) {
|
||||||
|
nodeItem.prompts = prompts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.type === CHAIN_SUMMARIZATION_LANGCHAIN_NODE_TYPE) {
|
||||||
|
nodeItem.prompts = (
|
||||||
|
(((node.parameters?.options as IDataObject) || {})
|
||||||
|
.summarizationMethodAndPrompts as IDataObject) || {}
|
||||||
|
).values as IDataObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LANGCHAIN_CUSTOM_TOOLS.includes(node.type)) {
|
||||||
|
nodeItem.prompts = {
|
||||||
|
description: (node.parameters?.description as string) || '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nodeGraph.nodes[index.toString()] = nodeItem;
|
nodeGraph.nodes[index.toString()] = nodeItem;
|
||||||
nameIndices[node.name] = index.toString();
|
nameIndices[node.name] = index.toString();
|
||||||
});
|
});
|
||||||
|
|
|
@ -52,7 +52,11 @@ import * as NodeHelpers from './NodeHelpers';
|
||||||
import * as ObservableObject from './ObservableObject';
|
import * as ObservableObject from './ObservableObject';
|
||||||
import { RoutingNode } from './RoutingNode';
|
import { RoutingNode } from './RoutingNode';
|
||||||
import { Expression } from './Expression';
|
import { Expression } from './Expression';
|
||||||
import { NODES_WITH_RENAMABLE_CONTENT } from './Constants';
|
import {
|
||||||
|
MANUAL_CHAT_TRIGGER_LANGCHAIN_NODE_TYPE,
|
||||||
|
NODES_WITH_RENAMABLE_CONTENT,
|
||||||
|
STARTING_NODE_TYPES,
|
||||||
|
} from './Constants';
|
||||||
import { ApplicationError } from './errors/application.error';
|
import { ApplicationError } from './errors/application.error';
|
||||||
|
|
||||||
function dedupe<T>(arr: T[]): T[] {
|
function dedupe<T>(arr: T[]): T[] {
|
||||||
|
@ -990,7 +994,7 @@ export class Workflow {
|
||||||
nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
||||||
|
|
||||||
// TODO: Identify later differently
|
// TODO: Identify later differently
|
||||||
if (nodeType.description.name === '@n8n/n8n-nodes-langchain.manualChatTrigger') {
|
if (nodeType.description.name === MANUAL_CHAT_TRIGGER_LANGCHAIN_NODE_TYPE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,20 +1006,13 @@ export class Workflow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const startingNodeTypes = [
|
|
||||||
'n8n-nodes-base.manualTrigger',
|
|
||||||
'n8n-nodes-base.executeWorkflowTrigger',
|
|
||||||
'n8n-nodes-base.errorTrigger',
|
|
||||||
'n8n-nodes-base.start',
|
|
||||||
];
|
|
||||||
|
|
||||||
const sortedNodeNames = Object.values(this.nodes)
|
const sortedNodeNames = Object.values(this.nodes)
|
||||||
.sort((a, b) => startingNodeTypes.indexOf(a.type) - startingNodeTypes.indexOf(b.type))
|
.sort((a, b) => STARTING_NODE_TYPES.indexOf(a.type) - STARTING_NODE_TYPES.indexOf(b.type))
|
||||||
.map((n) => n.name);
|
.map((n) => n.name);
|
||||||
|
|
||||||
for (const nodeName of sortedNodeNames) {
|
for (const nodeName of sortedNodeNames) {
|
||||||
node = this.nodes[nodeName];
|
node = this.nodes[nodeName];
|
||||||
if (startingNodeTypes.includes(node.type)) {
|
if (STARTING_NODE_TYPES.includes(node.type)) {
|
||||||
if (node.disabled === true) {
|
if (node.disabled === true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import { augmentArray, augmentObject } from './AugmentObject';
|
||||||
import { deepCopy } from './utils';
|
import { deepCopy } from './utils';
|
||||||
import { getGlobalState } from './GlobalState';
|
import { getGlobalState } from './GlobalState';
|
||||||
import { ApplicationError } from './errors/application.error';
|
import { ApplicationError } from './errors/application.error';
|
||||||
|
import { SCRIPTING_NODE_TYPES } from './Constants';
|
||||||
|
|
||||||
export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator {
|
export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator {
|
||||||
return Boolean(
|
return Boolean(
|
||||||
|
@ -35,12 +36,6 @@ export function isResourceLocatorValue(value: unknown): value is INodeParameterR
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SCRIPTING_NODE_TYPES = [
|
|
||||||
'n8n-nodes-base.function',
|
|
||||||
'n8n-nodes-base.functionItem',
|
|
||||||
'n8n-nodes-base.code',
|
|
||||||
];
|
|
||||||
|
|
||||||
const isScriptingNode = (nodeName: string, workflow: Workflow) => {
|
const isScriptingNode = (nodeName: string, workflow: Workflow) => {
|
||||||
const node = workflow.getNode(nodeName);
|
const node = workflow.getNode(nodeName);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { NodeError } from './abstract/node.error';
|
||||||
import { removeCircularRefs } from '../utils';
|
import { removeCircularRefs } from '../utils';
|
||||||
import type { ReportingOptions } from './application.error';
|
import type { ReportingOptions } from './application.error';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
|
import { NO_OP_NODE_TYPE } from '../Constants';
|
||||||
|
|
||||||
export interface NodeOperationErrorOptions {
|
export interface NodeOperationErrorOptions {
|
||||||
message?: string;
|
message?: string;
|
||||||
|
@ -282,7 +283,7 @@ export class NodeApiError extends NodeError {
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||||
this.message = this.message || this.description || UNKNOWN_ERROR_MESSAGE;
|
this.message = this.message || this.description || UNKNOWN_ERROR_MESSAGE;
|
||||||
}
|
}
|
||||||
if (this.node.type === 'n8n-nodes-base.noOp' && this.message === UNKNOWN_ERROR_MESSAGE) {
|
if (this.node.type === NO_OP_NODE_TYPE && this.message === UNKNOWN_ERROR_MESSAGE) {
|
||||||
this.message = `${UNKNOWN_ERROR_MESSAGE_CRED} - ${this.httpCode}`;
|
this.message = `${UNKNOWN_ERROR_MESSAGE_CRED} - ${this.httpCode}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue