mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 18:41:14 +00:00
feat(core): Expose $agentInfo variable for easy AI workflow (no-changelog) (#14445)
Co-authored-by: Mutasem Aldmour <mutasem@n8n.io>
This commit is contained in:
@@ -6,29 +6,30 @@ import * as jmespath from 'jmespath';
|
||||
import { DateTime, Duration, Interval, Settings } from 'luxon';
|
||||
|
||||
import { augmentArray, augmentObject } from './AugmentObject';
|
||||
import { SCRIPTING_NODE_TYPES } from './Constants';
|
||||
import { AGENT_LANGCHAIN_NODE_TYPE, SCRIPTING_NODE_TYPES } from './Constants';
|
||||
import { ApplicationError } from './errors/application.error';
|
||||
import { ExpressionError, type ExpressionErrorOptions } from './errors/expression.error';
|
||||
import { getGlobalState } from './GlobalState';
|
||||
import {
|
||||
type IDataObject,
|
||||
type IExecuteData,
|
||||
type INodeExecutionData,
|
||||
type INodeParameters,
|
||||
type IPairedItemData,
|
||||
type IRunExecutionData,
|
||||
type ISourceData,
|
||||
type ITaskData,
|
||||
type IWorkflowDataProxyAdditionalKeys,
|
||||
type IWorkflowDataProxyData,
|
||||
type INodeParameterResourceLocator,
|
||||
type NodeParameterValueType,
|
||||
type WorkflowExecuteMode,
|
||||
type ProxyInput,
|
||||
NodeConnectionTypes,
|
||||
import { NodeConnectionTypes } from './Interfaces';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteData,
|
||||
INodeExecutionData,
|
||||
INodeParameters,
|
||||
IPairedItemData,
|
||||
IRunExecutionData,
|
||||
ISourceData,
|
||||
ITaskData,
|
||||
IWorkflowDataProxyAdditionalKeys,
|
||||
IWorkflowDataProxyData,
|
||||
INodeParameterResourceLocator,
|
||||
NodeParameterValueType,
|
||||
WorkflowExecuteMode,
|
||||
ProxyInput,
|
||||
INode,
|
||||
} from './Interfaces';
|
||||
import * as NodeHelpers from './NodeHelpers';
|
||||
import { deepCopy } from './utils';
|
||||
import { deepCopy, isObjectEmpty } from './utils';
|
||||
import type { Workflow } from './Workflow';
|
||||
import type { EnvProviderState } from './WorkflowDataProxyEnvProvider';
|
||||
import { createEnvProvider, createEnvProviderState } from './WorkflowDataProxyEnvProvider';
|
||||
@@ -159,6 +160,89 @@ export class WorkflowDataProxy {
|
||||
);
|
||||
}
|
||||
|
||||
private buildAgentToolInfo(node: INode) {
|
||||
const nodeType = this.workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
||||
const type = nodeType.description.displayName;
|
||||
const params = NodeHelpers.getNodeParameters(
|
||||
nodeType.description.properties,
|
||||
node.parameters,
|
||||
true,
|
||||
false,
|
||||
node,
|
||||
nodeType.description,
|
||||
);
|
||||
const resourceKey = params?.resource;
|
||||
const operationKey = params?.operation;
|
||||
|
||||
const resource =
|
||||
nodeType.description.properties
|
||||
.find((nodeProperties) => nodeProperties.name === 'resource')
|
||||
?.options?.find((option) => 'value' in option && option.value === resourceKey)?.name ??
|
||||
null;
|
||||
|
||||
const operation =
|
||||
nodeType.description.properties
|
||||
.find(
|
||||
(nodeProperty) =>
|
||||
nodeProperty.name === 'operation' &&
|
||||
nodeProperty.displayOptions?.show?.resource?.some((y) => y === resourceKey),
|
||||
)
|
||||
?.options?.find((y) => 'value' in y && y.value === operationKey)?.name ?? null;
|
||||
|
||||
const hasCredentials = !isObjectEmpty(node.credentials ?? {});
|
||||
|
||||
const hasValidCalendar = nodeType.description.name.includes('googleCalendar')
|
||||
? isResourceLocatorValue(node.parameters.calendar) && node.parameters.calendar.value !== ''
|
||||
: undefined;
|
||||
|
||||
const aiDefinedFields = Object.entries(node.parameters)
|
||||
.map(([key, value]) => [key, isResourceLocatorValue(value) ? value.value : value] as const)
|
||||
.filter(([_, value]) => value?.toString().toLowerCase().includes('$fromai'))
|
||||
.map(
|
||||
([key]) =>
|
||||
nodeType.description.properties.find((property) => property.name === key)?.displayName,
|
||||
);
|
||||
|
||||
return {
|
||||
name: node.name,
|
||||
type,
|
||||
resource,
|
||||
operation,
|
||||
hasCredentials,
|
||||
hasValidCalendar,
|
||||
aiDefinedFields,
|
||||
};
|
||||
}
|
||||
|
||||
private agentInfo() {
|
||||
const agentNode = this.workflow.getNode(this.activeNodeName);
|
||||
if (!agentNode || agentNode.type !== AGENT_LANGCHAIN_NODE_TYPE) return undefined;
|
||||
const connectedTools = this.workflow
|
||||
.getParentNodes(this.activeNodeName, NodeConnectionTypes.AiTool)
|
||||
.map((nodeName) => this.workflow.getNode(nodeName))
|
||||
.filter((node) => node) as INode[];
|
||||
const memoryConnectedToAgent =
|
||||
this.workflow.getParentNodes(this.activeNodeName, NodeConnectionTypes.AiMemory).length > 0;
|
||||
const allTools = this.workflow.queryNodes((nodeType) => {
|
||||
return nodeType.description.name.toLowerCase().includes('tool');
|
||||
});
|
||||
|
||||
const unconnectedTools = allTools
|
||||
.filter(
|
||||
(node) =>
|
||||
this.workflow.getChildNodes(node.name, NodeConnectionTypes.AiTool, 1).length === 0,
|
||||
)
|
||||
.filter((node) => !connectedTools.includes(node));
|
||||
|
||||
return {
|
||||
memoryConnectedToAgent,
|
||||
tools: [
|
||||
...connectedTools.map((node) => ({ connected: true, ...this.buildAgentToolInfo(node) })),
|
||||
...unconnectedTools.map((node) => ({ connected: false, ...this.buildAgentToolInfo(node) })),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a proxy which allows to query parameter data of a given node
|
||||
*
|
||||
@@ -1394,6 +1478,7 @@ export class WorkflowDataProxy {
|
||||
$thisRunIndex: this.runIndex,
|
||||
$nodeVersion: that.workflow.getNode(that.activeNodeName)?.typeVersion,
|
||||
$nodeId: that.workflow.getNode(that.activeNodeName)?.id,
|
||||
$agentInfo: this.agentInfo(),
|
||||
$webhookId: that.workflow.getNode(that.activeNodeName)?.webhookId,
|
||||
};
|
||||
const throwOnMissingExecutionData = opts?.throwOnMissingExecutionData ?? true;
|
||||
|
||||
Reference in New Issue
Block a user