mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -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(
|
||||
workflowData as IWorkflowBase,
|
||||
this.workflowHelpers.getNodeTypes(),
|
||||
{ isCloudDeployment: this.settingsStore.isCloudDeployment },
|
||||
).nodeGraph,
|
||||
),
|
||||
};
|
||||
|
@ -1991,6 +1992,7 @@ export default defineComponent({
|
|||
TelemetryHelpers.generateNodesGraph(
|
||||
workflowData as IWorkflowBase,
|
||||
this.workflowHelpers.getNodeTypes(),
|
||||
{ isCloudDeployment: this.settingsStore.isCloudDeployment },
|
||||
).nodeGraph,
|
||||
),
|
||||
};
|
||||
|
@ -2147,6 +2149,7 @@ export default defineComponent({
|
|||
workflowData.meta && workflowData.meta.instanceId !== currInstanceId
|
||||
? workflowData.meta.instanceId
|
||||
: '',
|
||||
isCloudDeployment: this.settingsStore.isCloudDeployment,
|
||||
},
|
||||
).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_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
|
||||
export const CREDENTIAL_EMPTY_VALUE =
|
||||
'__n8n_EMPTY_VALUE_7b1af746-3729-4c60-9b9b-e08eb29e58da' as const;
|
||||
|
||||
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_instance_id?: string;
|
||||
agent?: string; //@n8n/n8n-nodes-langchain.agent
|
||||
prompts?: IDataObject[] | IDataObject; //ai node's prompts, cloud only
|
||||
}
|
||||
|
||||
export interface INodeNameIndex {
|
||||
|
|
|
@ -8,10 +8,18 @@ import type {
|
|||
INodesGraphResult,
|
||||
IWorkflowBase,
|
||||
INodeTypes,
|
||||
IDataObject,
|
||||
} from './Interfaces';
|
||||
import { ApplicationError } from './errors/application.error';
|
||||
|
||||
const STICKY_NODE_TYPE = 'n8n-nodes-base.stickyNote';
|
||||
import {
|
||||
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 {
|
||||
return workflow.nodes.find((node) => node.name === nodeName);
|
||||
|
@ -95,6 +103,7 @@ export function generateNodesGraph(
|
|||
options?: {
|
||||
sourceInstanceId?: string;
|
||||
nodeIdMap?: { [curr: string]: string };
|
||||
isCloudDeployment?: boolean;
|
||||
},
|
||||
): INodesGraphResult {
|
||||
const nodeGraph: INodesGraph = {
|
||||
|
@ -158,15 +167,15 @@ export function generateNodesGraph(
|
|||
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';
|
||||
} else if (node.type === 'n8n-nodes-base.httpRequest' && node.typeVersion === 1) {
|
||||
} else if (node.type === HTTP_REQUEST_NODE_TYPE && node.typeVersion === 1) {
|
||||
try {
|
||||
nodeItem.domain = new URL(node.parameters.url as string).hostname;
|
||||
} catch {
|
||||
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 };
|
||||
|
||||
nodeItem.credential_type = {
|
||||
|
@ -182,7 +191,7 @@ export function generateNodesGraph(
|
|||
nodeItem.domain_base = getDomainBase(url);
|
||||
nodeItem.domain_path = getDomainPath(url);
|
||||
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);
|
||||
} else {
|
||||
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;
|
||||
nameIndices[node.name] = index.toString();
|
||||
});
|
||||
|
|
|
@ -52,7 +52,11 @@ import * as NodeHelpers from './NodeHelpers';
|
|||
import * as ObservableObject from './ObservableObject';
|
||||
import { RoutingNode } from './RoutingNode';
|
||||
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';
|
||||
|
||||
function dedupe<T>(arr: T[]): T[] {
|
||||
|
@ -990,7 +994,7 @@ export class Workflow {
|
|||
nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
||||
|
||||
// TODO: Identify later differently
|
||||
if (nodeType.description.name === '@n8n/n8n-nodes-langchain.manualChatTrigger') {
|
||||
if (nodeType.description.name === MANUAL_CHAT_TRIGGER_LANGCHAIN_NODE_TYPE) {
|
||||
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)
|
||||
.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);
|
||||
|
||||
for (const nodeName of sortedNodeNames) {
|
||||
node = this.nodes[nodeName];
|
||||
if (startingNodeTypes.includes(node.type)) {
|
||||
if (STARTING_NODE_TYPES.includes(node.type)) {
|
||||
if (node.disabled === true) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import { augmentArray, augmentObject } from './AugmentObject';
|
|||
import { deepCopy } from './utils';
|
||||
import { getGlobalState } from './GlobalState';
|
||||
import { ApplicationError } from './errors/application.error';
|
||||
import { SCRIPTING_NODE_TYPES } from './Constants';
|
||||
|
||||
export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator {
|
||||
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 node = workflow.getNode(nodeName);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import { NodeError } from './abstract/node.error';
|
|||
import { removeCircularRefs } from '../utils';
|
||||
import type { ReportingOptions } from './application.error';
|
||||
import { AxiosError } from 'axios';
|
||||
import { NO_OP_NODE_TYPE } from '../Constants';
|
||||
|
||||
export interface NodeOperationErrorOptions {
|
||||
message?: string;
|
||||
|
@ -282,7 +283,7 @@ export class NodeApiError extends NodeError {
|
|||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
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}`;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue