UNPKG

n8n

Version:

n8n Workflow Automation Tool

298 lines • 14.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.buildFromJson = buildFromJson; const tool_1 = require("@n8n/agents/tool"); const zod_1 = require("zod"); const credential_field_mapping_1 = require("./credential-field-mapping"); const native_web_search_provider_tools_1 = require("./native-web-search-provider-tools"); const provider_tool_aliases_1 = require("./provider-tool-aliases"); const WEB_SEARCH_TOOL_NAME = 'web_search'; const WEB_SEARCH_INPUT_SCHEMA = zod_1.z.object({ query: zod_1.z.string().min(1).describe('Search query'), maxResults: zod_1.z.number().int().min(1).max(10).optional().describe('Maximum number of results'), includeDomains: zod_1.z.array(zod_1.z.string()).optional().describe('Only return results from these domains'), excludeDomains: zod_1.z.array(zod_1.z.string()).optional().describe('Exclude results from these domains'), }); async function buildFromJson(config, toolDescriptors, options) { const { Agent } = await Promise.resolve().then(() => __importStar(require('@n8n/agents'))); const agent = new Agent(config.name); const resolvedModelConfig = await resolveModelConfig(config, options.credentialProvider); agent.model(resolvedModelConfig); const configuredSkills = getConfiguredSkills(config.skills ?? [], options.skills ?? {}); agent.instructions(config.instructions); if (config.tools) { for (const ref of config.tools) { const built = await resolveToolRef(ref, toolDescriptors, options); if (built) { agent.tool(built); } } } if (config.mcpServers?.length && options.buildMcpClient) { for (const server of config.mcpServers) { const client = await options.buildMcpClient(server); agent.mcp(client); } } agent.skills(configuredSkills); const providerTools = (0, native_web_search_provider_tools_1.getNativeWebSearchProviderTools)(config, { includeDefaultArgs: false }); if (providerTools) { for (const [name, args] of Object.entries(providerTools)) { const resolved = (0, provider_tool_aliases_1.resolveProviderToolName)(name); agent.providerTool({ name: resolved, args }); } } const fallbackWebSearchTool = buildFallbackWebSearchTool(config, options.credentialProvider); if (fallbackWebSearchTool) { agent.tool(fallbackWebSearchTool); } if (config.memory?.enabled) { await applyMemoryFromConfig(agent, config.memory, options.memoryFactory, options.credentialProvider); } if (config.config) { if (config.config.thinking) { const { provider, ...rest } = config.config.thinking; agent.thinking(provider, rest); } if (config.config.toolCallConcurrency) { agent.toolCallConcurrency(config.config.toolCallConcurrency); } if (config.config.maxIterations) { agent.configuration({ maxIterations: config.config.maxIterations }); } } return agent; } function buildFallbackWebSearchTool(config, credentialProvider) { const webSearchConfig = config.config?.webSearch; if (!webSearchConfig?.enabled) return null; if ((0, native_web_search_provider_tools_1.isNativeWebSearchRequested)(config) && (0, native_web_search_provider_tools_1.hasNativeWebSearchProvider)(config.model)) return null; if (webSearchConfig.provider !== 'brave' && webSearchConfig.provider !== 'searxng') { throw new Error('Web search is enabled but no fallback search provider is configured.'); } if (!webSearchConfig.credential) { throw new Error('Web search is enabled but no search credential is configured.'); } const credentialId = webSearchConfig.credential; return { name: WEB_SEARCH_TOOL_NAME, description: 'Search the web for current information.', systemInstruction: 'Before using web_search, choose the smallest search plan that can answer the user. Default to one broad, high-signal query. After each search, stop if the results already contain enough credible sources to answer. Use a second search only when the first result set is insufficient or the user asked for comparison across independent source categories. Do not fan out variations of the same query, and do not search for confirmation only. Use more than two searches only when the user explicitly asks for deep research, exhaustive coverage, or multiple independent topics.', inputSchema: WEB_SEARCH_INPUT_SCHEMA, handler: async (input) => { const args = WEB_SEARCH_INPUT_SCHEMA.parse(input); const credential = await credentialProvider.resolve(credentialId); const { braveSearch, searxngSearch } = await Promise.resolve().then(() => __importStar(require('@n8n/ai-utilities'))); if (webSearchConfig.provider === 'brave') { if (typeof credential.apiKey !== 'string') { throw new Error('Brave Search credential is missing an API key.'); } return await braveSearch(credential.apiKey, args.query, { maxResults: args.maxResults, includeDomains: args.includeDomains, excludeDomains: args.excludeDomains, }); } if (typeof credential.apiUrl !== 'string') { throw new Error('SearXNG credential is missing an API URL.'); } return await searxngSearch(credential.apiUrl, args.query, { maxResults: args.maxResults, includeDomains: args.includeDomains, excludeDomains: args.excludeDomains, }); }, }; } function getConfiguredSkills(refs, skills) { const seen = new Set(); const configured = []; for (const ref of refs) { if (seen.has(ref.id)) continue; seen.add(ref.id); const skill = skills[ref.id]; if (!skill) throw new Error(`Skill "${ref.id}" not found in stored skill bodies`); configured.push({ id: ref.id, name: skill.name, description: skill.description, instructions: skill.instructions, }); } return configured; } async function resolveToolRef(ref, descriptors, options) { switch (ref.type) { case 'custom': { const descriptor = descriptors[ref.id]; if (!descriptor) { throw new Error(`Custom tool "${ref.id}" not found in tool descriptors`); } const builtTool = { name: descriptor.name, description: descriptor.description, systemInstruction: descriptor.systemInstruction ?? undefined, inputSchema: descriptor.inputSchema ?? undefined, handler: async (input, ctx) => { return await options.toolExecutor.executeTool(descriptor.name, input, { resumeData: 'resumeData' in ctx ? ctx.resumeData : undefined, parentTelemetry: ctx.parentTelemetry, }); }, providerOptions: descriptor.providerOptions, }; if (ref.requireApproval) { return (0, tool_1.wrapToolForApproval)(builtTool, { requireApproval: true }); } return builtTool; } case 'workflow': { const marker = { name: ref.name ?? ref.workflow, description: ref.description ?? `Execute the "${ref.workflow}" workflow`, editable: false, metadata: { workflowTool: true, workflowName: ref.workflow, options: { name: ref.name, description: ref.description }, }, }; const tool = (await options.resolveTool?.(ref)) ?? marker; if (ref.requireApproval) { return (0, tool_1.wrapToolForApproval)(tool, { requireApproval: true }); } return tool; } case 'node': { const marker = { name: ref.name, description: ref.description ?? `Execute node ${ref.name}`, editable: false, metadata: { nodeTool: true, ...ref.node }, }; const tool = (await options.resolveTool?.(ref)) ?? marker; if (ref.requireApproval) { return (0, tool_1.wrapToolForApproval)(tool, { requireApproval: true }); } return tool; } } } async function applyMemoryFromConfig(agent, memoryConfig, memoryFactory, credentialProvider) { const { Memory } = await Promise.resolve().then(() => __importStar(require('@n8n/agents'))); const memory = new Memory(); const builtMemory = memoryFactory(memoryConfig); memory.storage(await Promise.resolve(builtMemory)); if (memoryConfig.semanticRecall) { memory.semanticRecall(memoryConfig.semanticRecall); } if (memoryConfig.episodicMemory?.enabled === true) { memory.episodicMemory(await resolveEpisodicMemoryJsonConfig(memoryConfig.episodicMemory, credentialProvider)); } if (memoryConfig.observationalMemory?.enabled !== false) { const observationalMemory = memoryConfig.observationalMemory; const { createObservationLogObserveFn, createObservationLogReflectFn } = await Promise.resolve().then(() => __importStar(require('@n8n/agents'))); memory.observationalMemory({ ...(observationalMemory?.observerModel !== undefined && { observe: createObservationLogObserveFn(await resolveMemoryWorkerModelConfig(observationalMemory.observerModel, credentialProvider)), }), ...(observationalMemory?.reflectorModel !== undefined && { reflect: createObservationLogReflectFn(await resolveMemoryWorkerModelConfig(observationalMemory.reflectorModel, credentialProvider)), }), ...(observationalMemory?.observerThresholdTokens !== undefined && { observerThresholdTokens: observationalMemory.observerThresholdTokens, }), ...(observationalMemory?.reflectorThresholdTokens !== undefined && { reflectorThresholdTokens: observationalMemory.reflectorThresholdTokens, }), ...(observationalMemory?.renderTokenBudget !== undefined && { renderTokenBudget: observationalMemory.renderTokenBudget, }), ...(observationalMemory?.observationLogTailLimit !== undefined && { observationLogTailLimit: observationalMemory.observationLogTailLimit, }), ...(observationalMemory?.lockTtlMs !== undefined && { lockTtlMs: observationalMemory.lockTtlMs, }), }); } memory.titleGeneration({ sync: true }); agent.memory(memory); } async function resolveEpisodicMemoryJsonConfig(config, credentialProvider) { const { DEFAULT_EPISODIC_MEMORY_EMBEDDING_MODEL, createEpisodicMemoryExtractFn, createEpisodicMemoryReflectFn, } = await Promise.resolve().then(() => __importStar(require('@n8n/agents'))); const embeddingModel = DEFAULT_EPISODIC_MEMORY_EMBEDDING_MODEL; const raw = await credentialProvider.resolve(config.credential); const mapped = (0, credential_field_mapping_1.mapCredentialForProvider)(getProviderPrefix(embeddingModel), raw); const embeddingProviderOptions = { ...(typeof mapped.apiKey === 'string' && { apiKey: mapped.apiKey }), ...(typeof mapped.baseURL === 'string' && { baseURL: mapped.baseURL }), }; return { enabled: true, ...(config.extractorModel !== undefined && { extract: createEpisodicMemoryExtractFn(await resolveMemoryWorkerModelConfig(config.extractorModel, credentialProvider)), }), ...(config.reflectorModel !== undefined && { reflect: createEpisodicMemoryReflectFn(await resolveMemoryWorkerModelConfig(config.reflectorModel, credentialProvider)), }), ...(config.topK !== undefined && { topK: config.topK }), ...(config.maxEntriesPerRun !== undefined && { maxEntriesPerRun: config.maxEntriesPerRun }), embeddingProviderOptions, }; } async function resolveModelConfig(config, credentialProvider) { if (!config.credential) return config.model; return await resolveCredentialAwareModelConfig(config.model, config.credential, credentialProvider); } async function resolveMemoryWorkerModelConfig(config, credentialProvider) { return await resolveCredentialAwareModelConfig(config.model, config.credential, credentialProvider); } async function resolveCredentialAwareModelConfig(model, credential, credentialProvider) { const raw = await credentialProvider.resolve(credential); const mapped = (0, credential_field_mapping_1.mapCredentialForProvider)(getProviderPrefix(model), raw); return { id: model, ...mapped }; } function getProviderPrefix(modelId) { const slashIdx = modelId.indexOf('/'); return slashIdx !== -1 ? modelId.slice(0, slashIdx) : ''; } //# sourceMappingURL=from-json-config.js.map