@cognigy/rest-api-client
Version:
Cognigy REST-Client
223 lines • 10.9 kB
JavaScript
;
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