UNPKG

@cognigy/rest-api-client

Version:

Cognigy REST-Client

223 lines 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.safeParseJson = exports.createToolDefinitions = void 0; const createSystemMessage_1 = require("./createSystemMessage"); const parseMcpHeaders_1 = require("./parseMcpHeaders"); /** * Creates the tool definitions for the AI Agent Job and LLM Prompt v2 Nodes * @param childConfigs Child node configurations * @param api Cognigy API * @param useStrict Whether to use strict mode for the tools * @returns An object containing the tool definitions */ const createToolDefinitions = async (childConfigs, api, useStrict) => { var _a, _b, _c; // Create Tools JSON /** This is the list of tools that are used in the AI Agent Job */ const tools = []; /** Array of tool IDs for deduping */ const toolIds = []; /** Map of MCP tool IDs to their respective node IDs they were loaded from */ const toolMap = new Map(); /** Array of tool names for listing in the debug message */ const toolNames = []; // if no child configs are provided, return empty tool definitions if (!childConfigs || childConfigs.length === 0) { return { toolIds: [], toolNames: [], toolMap: new Map(), tools: [], }; } // Loop through all child nodes and create the tools for (const child of childConfigs) { if (child.type === "aiAgentJobDefault" || child.type === "llmPromptDefault") { continue; } const toolId = child.config.toolId; if ((child.type === "aiAgentJobMCPTool" || child.type === "llmPromptMCPTool") && (!child.config.condition || !!await api.parseCognigyScriptCondition(child.config.condition))) { if (!child.config.mcpServerUrl) { throw new Error(`MCP Server URL is missing in Tool Node configuration.`); } const mcpServerUrl = child.config.mcpServerUrl; const timeout = child.config.timeout; const cacheTools = child.config.cacheTools; const sendDebug = child.config.debugMessageFetchedTools; const toolFilter = child.config.toolFilter; // Parse mcpHeaders values if present and resolve any Cognigy script expressions const mcpHeaders = await (0, parseMcpHeaders_1.parseMcpHeaders)(child.config.mcpHeaders, api); let mcpTools = null; let fetchedFromCache = null; try { const fetched = await api.fetchMcpTools({ mcpServerUrl, timeout, cacheTools, mcpHeaders, authType: child.config.authType, oAuth2Connection: child.config.authType === "oAuth2" ? { oAuth2Url: child.config.oAuth2Connection.oAuth2Url, oAuth2ClientId: child.config.oAuth2Connection.oAuth2ClientId, oAuth2ClientSecret: child.config.oAuth2Connection.oAuth2ClientSecret, oAuth2Scope: child.config.oAuth2Connection.oAuth2Scope, } : undefined, }); mcpTools = fetched.tools; fetchedFromCache = fetched.fromCache; } catch (error) { const errorDetails = error instanceof Error ? { name: error.name, message: error.message, } : error; (_a = api.logDebugError) === null || _a === void 0 ? void 0 : _a.call(api, `Unable to connect to MCP Server:<br>${JSON.stringify(errorDetails, null, 2)}`, child.config.name); } if (mcpTools) { if (sendDebug) { const sourceLabel = fetchedFromCache ? "from cache" : "from MCP server"; if (mcpTools.length === 0) { (_b = api.logDebugMessage) === null || _b === void 0 ? void 0 : _b.call(api, `No tools fetched from MCP Tool "${child.config.name}" (${sourceLabel}).`, "MCP Tool"); } if (mcpTools.length > 0) { const messageLines = [`Fetched tools from MCP Tool "${child.config.name}" (${sourceLabel})`]; mcpTools.forEach((tool) => { messageLines.push(`<br>- <b>${tool.name}</b>: ${tool.description}`); if (child.config.debugMessageParameters && tool.inputSchema) { messageLines.push(` <b>Parameters</b>:`); Object.keys(tool.inputSchema.properties).forEach((key) => { const parameter = tool.inputSchema.properties[key]; const requiredText = tool.inputSchema.required && !tool.inputSchema.required.includes(key) ? " (optional)" : ""; if (parameter.description) { messageLines.push(` - ${key} (${parameter.type}): ${parameter.description}${requiredText}`); } else { messageLines.push(` - ${key}: ${parameter.type}${requiredText}`); } }); } }); (_c = api.logDebugMessage) === null || _c === void 0 ? void 0 : _c.call(api, messageLines.join("\n"), "MCP Tool"); } } const filteredMcpTools = mcpTools.filter((tool) => { if (toolFilter && toolFilter !== "none") { if (toolFilter === "whitelist" && child.config.whitelist) { const whitelist = child.config.whitelist.map((item) => item.trim()); return whitelist.includes(tool.name); } else if (toolFilter === "blacklist") { // If the blacklist is falsy, all tools are allowed if (!child.config.blacklist) { return true; } const blacklist = child.config.blacklist.map((item) => item.trim()); return !blacklist.includes(tool.name); } } else { return true; } }); const structuredMcpTools = []; filteredMcpTools.forEach((tool) => { var _a; if (toolIds.includes(tool.name)) { (_a = api.logDebugError) === null || _a === void 0 ? void 0 : _a.call(api, `Tool "${tool.name}" from MCP Tool "${child.config.name}" is not unique and will not be added. Please ensure each tool has a unique id.`); return; } // add tool to the list of tool ids to prevent duplicates toolIds.push(tool.name); toolNames.push(`${tool.name} (${child.config.name})`); toolMap.set(tool.name, child.id); const structuredTool = { type: "function", function: { name: tool.name, description: tool.description, }, }; if (tool.inputSchema) { structuredTool.function.parameters = tool.inputSchema; } structuredMcpTools.push(structuredTool); }); tools.push(...structuredMcpTools); } } if (!["llmPromptMCPTool", "aiAgentJobMCPTool"].includes(child.type) && (!child.config.condition || !!await api.parseCognigyScriptCondition(child.config.condition))) { if (!toolId) { throw new Error(`Tool ID is missing in Tool Node configuration.`); } const parsedToolId = await api.parseCognigyScriptText(toolId); if (!(0, createSystemMessage_1.validateToolId)(parsedToolId)) { throw new Error(`Tool ID ${parsedToolId} is not valid. Please use only alphanumeric characters, dashes and underscores.`); } if (toolIds.includes(parsedToolId)) { throw new Error(`Tool ID ${parsedToolId} is not unique. Please ensure each tool has a unique id.`); } toolIds.push(parsedToolId); toolNames.push(parsedToolId); const tool = { type: "function", function: { name: parsedToolId, description: await api.parseCognigyScriptText(child.config.description), }, }; if (useStrict) { tool.function.strict = true; } if (child.config.parameters && child.config.useParameters !== false) { const parameters = safeParseJson(child.config.parameters); if (parameters !== null) { tool.function.parameters = parameters; } } tools.push(tool); } } ; return { toolIds, toolNames, toolMap, tools, }; }; exports.createToolDefinitions = createToolDefinitions; /** * Safely parses JSON with backwards compatibility for trailing commas. * * The trailing comma cleanup is required for backwards compatibility with the * knowledge tool, which had invalid JSON (with trailing commas) in the initial * release. Although the JSON wasn't actually used at that time due to parameters not being used, * we need to handle it gracefully to support any stored configurations. * * @param raw - The value to parse. If already parsed (not a string), returns it as-is if truthy. * @returns The parsed JSON object, the input value if already parsed, or null if parsing fails or input is falsy. */ function safeParseJson(raw) { // If not a string, return as-is if truthy, otherwise null if (typeof raw !== "string") { return raw || null; } try { return JSON.parse(raw); } catch (_a) { // Fallback: remove trailing commas before } or ] const cleaned = raw.replace(/,\s*([}\]])/g, "$1"); try { return JSON.parse(cleaned); } catch (_b) { return null; // safe fallback instead of throwing } } } exports.safeParseJson = safeParseJson; //# sourceMappingURL=createToolDefinitions.js.map