UNPKG

n8n

Version:

n8n Workflow Automation Tool

193 lines 9.63 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.AgentsToolsService = exports.isAgentToolNodeType = exports.isExecutableNodeType = void 0; const agents_1 = require("@n8n/agents"); const backend_common_1 = require("@n8n/backend-common"); const di_1 = require("@n8n/di"); const workflow_sdk_1 = require("@n8n/workflow-sdk"); const n8n_workflow_1 = require("n8n-workflow"); const zod_1 = require("zod"); const node_execution_1 = require("../../node-execution"); const node_catalog_1 = require("../../node-catalog"); const isExecutableNodeType = (nodeId) => !(0, n8n_workflow_1.isTriggerNodeType)(nodeId); exports.isExecutableNodeType = isExecutableNodeType; const isAgentToolNodeType = (nodeId) => (0, exports.isExecutableNodeType)(nodeId) && ((0, n8n_workflow_1.isToolType)(nodeId, { includeHitl: false }) || (0, node_execution_1.isAgentProviderNode)(nodeId)); exports.isAgentToolNodeType = isAgentToolNodeType; const searchNodesInputSchema = zod_1.z.object({ queries: zod_1.z.array(zod_1.z.string()).min(1).describe('Search queries (e.g., ["gmail", "slack", "http"])'), }); const nodeVersionSchema = zod_1.z.number().describe('Tool node type version from search_nodes'); const getNodeTypesInputSchema = zod_1.z.object({ nodeIds: zod_1.z .array(zod_1.z.union([ zod_1.z.string(), zod_1.z.object({ nodeId: zod_1.z.string(), version: nodeVersionSchema.optional(), resource: zod_1.z.string().optional(), operation: zod_1.z.string().optional(), mode: zod_1.z.string().optional(), }), ])) .min(1) .describe('Tool node IDs from search_nodes (e.g., ["n8n-nodes-base.gmailTool"])'), }); const listCredentialsInputSchema = zod_1.z.object({ types: zod_1.z .array(zod_1.z.string()) .optional() .describe('Optional credential types to filter by (e.g., ["gmailOAuth2", "httpHeaderAuth"]). ' + 'When omitted, returns all credentials. Use the credential types declared in the ' + 'node schema from get_node_types to narrow the results.'), }); const runNodeInputSchema = zod_1.z.object({ nodeType: zod_1.z.string().describe('Tool node type identifier from search_nodes'), nodeTypeVersion: nodeVersionSchema, nodeParameters: zod_1.z .record(zod_1.z.unknown()) .optional() .describe('Static node config. Use expressions like ={{ $json.url }} to reference inputData fields.'), credentials: zod_1.z .record(zod_1.z.object({ id: zod_1.z.string(), name: zod_1.z.string() })) .optional() .describe('Credential slot → { id, name }. Copy from list_credentials results.'), inputData: zod_1.z .record(zod_1.z.unknown()) .optional() .describe('Runtime input, available as $json inside nodeParameters expressions.'), }); let AgentsToolsService = class AgentsToolsService { constructor(logger, nodeCatalogService, ephemeralNodeExecutor) { this.logger = logger; this.nodeCatalogService = nodeCatalogService; this.ephemeralNodeExecutor = ephemeralNodeExecutor; } getSharedTools(credentialProvider, listCredentialsUsageHint) { return [ this.buildSearchNodesTool(), this.buildGetNodeTypesTool(), this.buildListCredentialsTool(credentialProvider, listCredentialsUsageHint), ]; } getRuntimeTools(credentialProvider, projectId) { return [ ...this.getSharedTools(credentialProvider, 'Call this before run_node_tool to know which credential to pass.'), this.buildRunNodeTool(projectId), ]; } buildSearchNodesTool() { return new agents_1.Tool('search_nodes') .description('Search for n8n nodes by name or service. Use this to find nodes that can be executed. ' + 'Returns tool node IDs, display names, versions, and descriptions. ' + 'After finding a node, call get_node_types to get its parameter schema.') .input(searchNodesInputSchema) .handler(async ({ queries }) => { const { results } = await this.nodeCatalogService.searchNodes(queries, { nodeFilter: exports.isAgentToolNodeType, }); return { results }; }) .build(); } buildGetNodeTypesTool() { return new agents_1.Tool('get_node_types') .description('Get detailed parameter schema for specific n8n nodes. Use the node IDs returned ' + 'by search_nodes. Returns parameter definitions needed to configure a node for execution. ' + 'Use the tool node IDs from search_nodes. ' + 'You can optionally filter by resource/operation/mode.') .input(getNodeTypesInputSchema) .handler(async ({ nodeIds }) => { const results = await this.nodeCatalogService.getNodeTypes(nodeIds.map(normalizeNodeRequestForCatalog)); return { results }; }) .build(); } buildListCredentialsTool(credentialProvider, usageHint) { return new agents_1.Tool('list_credentials') .description('List the credentials available to the user. Returns an array of credential names and types. ' + 'Accepts an optional `types` filter to return only credentials matching the given types. ' + usageHint) .input(listCredentialsInputSchema) .handler(async ({ types }) => { const creds = await credentialProvider.list(); if (!types || types.length === 0) return { credentials: creds }; const allowed = new Set(types); return { credentials: creds.filter((c) => allowed.has(c.type)) }; }) .build(); } buildRunNodeTool(projectId) { return new agents_1.Tool('run_node_tool') .description('Execute an n8n node for the current request. ' + 'Use the tool nodeType and nodeTypeVersion from search_nodes. ' + 'Call get_node_types first to understand what nodeParameters the node accepts. ' + 'nodeParameters holds static node config; use n8n expressions like ={{ $json.url }} to map inputData fields. ' + 'credentials maps slot names to { id, name } — copy from the list_credentials results. ' + 'inputData is the runtime payload available as $json inside expressions. ' + 'Parameters are validated against the node schema before execution.') .input(runNodeInputSchema) .handler(async ({ nodeType, nodeTypeVersion, nodeParameters, credentials, inputData }) => { if (!(0, exports.isExecutableNodeType)(nodeType)) { return { status: 'error', message: `Node type "${nodeType}" cannot be executed directly — trigger nodes are not supported here.`, }; } if (nodeParameters) { const { valid, errors } = (0, workflow_sdk_1.validateNodeConfig)(nodeType, nodeTypeVersion, { parameters: nodeParameters, }, { isToolNode: true }); if (!valid) { return { status: 'error', message: `Invalid nodeParameters: ${errors.map((e) => e.message).join('; ')}`, }; } } try { return await this.ephemeralNodeExecutor.executeInline({ nodeType, nodeTypeVersion, nodeParameters: (nodeParameters ?? {}), credentialDetails: credentials, inputData: [{ json: (inputData ?? {}) }], projectId, }); } catch (error) { const message = error instanceof Error ? error.message : String(error); this.logger.warn('run_node_tool execution failed', { nodeType, error }); return { status: 'error', message: `Node execution failed: ${message}`, }; } }) .build(); } }; exports.AgentsToolsService = AgentsToolsService; exports.AgentsToolsService = AgentsToolsService = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [backend_common_1.Logger, node_catalog_1.NodeCatalogService, node_execution_1.EphemeralNodeExecutor]) ], AgentsToolsService); function normalizeNodeRequestForCatalog(req) { if (typeof req === 'string') return req; const { version, ...rest } = req; return version === undefined ? rest : { ...rest, version: String(version) }; } //# sourceMappingURL=agents-tools.service.js.map