UNPKG

n8n-nodes-sap-ai-core

Version:

n8n nodes for SAP AI Core LLM and embeddings integration

398 lines 13.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateSchemaFromExample = generateSchemaFromExample; exports.convertJsonSchemaToZod = convertJsonSchemaToZod; exports.validateJsonSchema = validateJsonSchema; exports.sanitizeSchema = sanitizeSchema; exports.prepareFallbackToolDescription = prepareFallbackToolDescription; exports.throwIfInvalidToolSchema = throwIfInvalidToolSchema; exports.extractSchemaFromTool = extractSchemaFromTool; exports.mergeSchemas = mergeSchemas; exports.createSchemaValidator = createSchemaValidator; exports.convertToOpenApiSchema = convertToOpenApiSchema; exports.simplifySchemaForSapAiCore = simplifySchemaForSapAiCore; const n8n_workflow_1 = require("n8n-workflow"); // Alternative JSON schema generation - using a simple implementation since external packages aren't available function generateSchemaFromObject(obj) { if (obj === null) return { type: 'null' }; if (typeof obj === 'boolean') return { type: 'boolean' }; if (typeof obj === 'number') return { type: 'number' }; if (typeof obj === 'string') return { type: 'string' }; if (Array.isArray(obj)) { return { type: 'array', items: obj.length > 0 ? generateSchemaFromObject(obj[0]) : { type: 'string' } }; } if (typeof obj === 'object') { const properties = {}; const required = []; for (const [key, value] of Object.entries(obj)) { properties[key] = generateSchemaFromObject(value); required.push(key); } return { type: 'object', properties, required }; } return { type: 'string' }; } /** * Check if a property schema is a valid property schema object */ function isPropertySchema(property) { return typeof property === "object" && property !== null && "type" in property; } /** * Make all properties in a schema required recursively */ function makeAllPropertiesRequired(schema) { if (schema.type === "object" && schema.properties) { const properties = Object.keys(schema.properties); if (properties.length > 0) { schema.required = properties; } // Recursively process nested objects for (const key of properties) { if (isPropertySchema(schema.properties[key])) { schema.properties[key] = makeAllPropertiesRequired(schema.properties[key]); } } } // Handle array items if (schema.type === "array" && schema.items && isPropertySchema(schema.items)) { schema.items = makeAllPropertiesRequired(schema.items); } return schema; } /** * Generate JSON schema from example JSON string */ function generateSchemaFromExample(exampleJsonString, allFieldsRequired = false) { try { const parsedExample = (0, n8n_workflow_1.jsonParse)(exampleJsonString); const schema = generateSchemaFromObject(parsedExample); if (allFieldsRequired) { return makeAllPropertiesRequired(schema); } return schema; } catch (error) { throw new Error(`Failed to generate schema from example: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Convert JSON schema to Zod-like schema (simplified implementation) */ function convertJsonSchemaToZod(schema) { // Since we don't have the actual zod library, we'll return a simplified representation // This should be replaced with actual zod conversion when the library is available try { return { _type: 'ZodSchema', _schema: schema, parse: (data) => { // Basic validation logic return validateDataAgainstSchema(data, schema); } }; } catch (error) { throw new Error(`Failed to convert JSON schema to Zod: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Basic validation function for data against schema */ function validateDataAgainstSchema(data, schema) { if (!schema || typeof schema !== 'object') { return data; } switch (schema.type) { case 'string': if (typeof data !== 'string') { throw new Error(`Expected string, got ${typeof data}`); } break; case 'number': if (typeof data !== 'number') { throw new Error(`Expected number, got ${typeof data}`); } break; case 'boolean': if (typeof data !== 'boolean') { throw new Error(`Expected boolean, got ${typeof data}`); } break; case 'array': if (!Array.isArray(data)) { throw new Error(`Expected array, got ${typeof data}`); } break; case 'object': if (typeof data !== 'object' || data === null || Array.isArray(data)) { throw new Error(`Expected object, got ${typeof data}`); } // Check required properties if (schema.required && Array.isArray(schema.required)) { for (const requiredProp of schema.required) { if (!(requiredProp in data)) { throw new Error(`Missing required property: ${requiredProp}`); } } } break; } return data; } /** * Validate a JSON schema */ function validateJsonSchema(schema) { try { // Basic validation - check for required fields if (typeof schema !== 'object' || schema === null) { return false; } // Must have a type if (!schema.type) { return false; } // If object type, should have properties if (schema.type === 'object' && !schema.properties) { return false; } // If array type, should have items if (schema.type === 'array' && !schema.items) { return false; } return true; } catch (error) { return false; } } /** * Sanitize schema by removing unsupported features */ function sanitizeSchema(schema) { // Remove $ref as they're not supported const sanitized = JSON.parse(JSON.stringify(schema)); function removeRefs(obj) { if (typeof obj !== 'object' || obj === null) { return obj; } if (Array.isArray(obj)) { return obj.map(removeRefs); } const result = {}; for (const [key, value] of Object.entries(obj)) { if (key === '$ref') { // Skip $ref properties continue; } result[key] = removeRefs(value); } return result; } return removeRefs(sanitized); } /** * Prepare fallback tool description with schema information */ function prepareFallbackToolDescription(toolDescription, schema) { let description = toolDescription || 'A tool for performing actions'; if (schema && schema.properties) { const toolParameters = Object.entries(schema.properties); if (toolParameters.length > 0) { description += `\n\nTool expects valid stringified JSON object with ${toolParameters.length} properties.`; description += '\nProperty names with description, type and required status:'; toolParameters.forEach(([name, paramSchema]) => { var _a, _b; const type = getSimplifiedType(paramSchema); const required = (_b = (_a = schema.required) === null || _a === void 0 ? void 0 : _a.includes(name)) !== null && _b !== void 0 ? _b : false; const paramDesc = paramSchema.description || ''; description += `\n${name}: (description: ${paramDesc}, type: ${type}, required: ${required})`; }); description += '\nALL parameters marked as required must be provided'; } } return description; } /** * Get simplified type from schema */ function getSimplifiedType(schema) { if (!schema || typeof schema !== 'object') { return 'string'; } // Handle Zod-like schemas if (schema._def) { const typeName = schema._def.typeName; switch (typeName) { case 'ZodObject': return 'object'; case 'ZodNumber': return 'number'; case 'ZodBoolean': return 'boolean'; case 'ZodArray': return 'array'; case 'ZodString': return 'string'; case 'ZodNullable': case 'ZodOptional': return getSimplifiedType(schema._def.innerType); default: return 'string'; } } // Handle JSON Schema if (schema.type) { switch (schema.type) { case 'object': return 'object'; case 'number': case 'integer': return 'number'; case 'boolean': return 'boolean'; case 'array': return 'array'; case 'string': default: return 'string'; } } return 'string'; } /** * Throw error if tool schema is invalid for SAP AI Core */ function throwIfInvalidToolSchema(ctx, error) { var _a; if ((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes("tool input did not match expected schema")) { throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `${error.message}. This is most likely because some of your tools are configured to require a specific schema. Please check the tool configuration and ensure the schema is valid for SAP AI Core. Tools should have proper JSON schema definitions with required fields marked correctly.`); } } /** * Extract schema from tool definition */ function extractSchemaFromTool(tool) { var _a; // Try different possible schema locations if (tool.schema) { return tool.schema; } if (tool.args_schema) { return tool.args_schema; } if (tool.parameters) { return tool.parameters; } if ((_a = tool.function) === null || _a === void 0 ? void 0 : _a.parameters) { return tool.function.parameters; } return null; } /** * Merge multiple schemas into one */ function mergeSchemas(schemas) { if (schemas.length === 0) { return { type: 'object', properties: {} }; } if (schemas.length === 1) { return schemas[0]; } const merged = { type: 'object', properties: {}, required: [] }; schemas.forEach(schema => { if (schema.properties) { Object.assign(merged.properties, schema.properties); } if (schema.required && Array.isArray(schema.required)) { merged.required.push(...schema.required); } }); // Remove duplicate required fields merged.required = [...new Set(merged.required)]; return merged; } /** * Create a basic schema validator */ function createSchemaValidator(schema) { return { validate: (data) => { try { validateDataAgainstSchema(data, schema); return { valid: true, errors: [] }; } catch (error) { return { valid: false, errors: [error instanceof Error ? error.message : String(error)] }; } }, schema }; } /** * Convert schema to OpenAPI format */ function convertToOpenApiSchema(schema) { if (!schema || typeof schema !== 'object') { return { type: 'string' }; } // Already in correct format if (schema.type) { return schema; } // Convert from other formats return generateSchemaFromObject(schema); } /** * Simplify complex schema for SAP AI Core compatibility */ function simplifySchemaForSapAiCore(schema) { if (!schema || typeof schema !== 'object') { return { type: 'string' }; } const simplified = { ...schema }; // Remove complex features not supported by SAP AI Core delete simplified.$schema; delete simplified.$id; delete simplified.definitions; delete simplified.allOf; delete simplified.anyOf; delete simplified.oneOf; delete simplified.not; // Simplify nested objects recursively if (simplified.properties) { const newProperties = {}; for (const [key, value] of Object.entries(simplified.properties)) { newProperties[key] = simplifySchemaForSapAiCore(value); } simplified.properties = newProperties; } // Simplify array items if (simplified.items) { simplified.items = simplifySchemaForSapAiCore(simplified.items); } return simplified; } //# sourceMappingURL=schemaParsing.js.map