UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and

428 lines (427 loc) 15 kB
/** * Object Transformation Utilities * Centralizes repeated object transformation patterns to improve code reuse and maintainability */ // ============================================================================ // TOOL EXECUTION TRANSFORMATIONS // ============================================================================ /** * Transform tool execution results from AI SDK format to NeuroLink GenerateResult format * Handles both single execution and array formats with robust type checking * * @param toolExecutions - Array of tool execution results from AI SDK (optional) * @returns Array of standardized tool execution objects with name, input, output, and duration * * @example * ```typescript * const executions = transformToolExecutions([ * { name: "calculator", input: { a: 5, b: 3 }, output: 8, duration: 150 } * ]); * // Returns: [{ name: "calculator", input: { a: 5, b: 3 }, output: 8, duration: 150 }] * ``` */ export function transformToolExecutions(toolExecutions) { if (!toolExecutions || !Array.isArray(toolExecutions)) { return []; } return toolExecutions.map((te, index) => { const teRecord = te; // Enhanced tool name extraction with multiple fallback strategies let toolName = teRecord.name || teRecord.toolName || teRecord.tool || ""; // If still no name, try to extract from nested objects if (!toolName && teRecord.toolCall && typeof teRecord.toolCall === "object") { const toolCall = teRecord.toolCall; toolName = toolCall.name || toolCall.toolName || ""; } // Last resort: use index-based fallback to avoid "Unknown Tool" if (!toolName) { toolName = `tool_execution_${index}`; } // Enhanced input extraction let input = teRecord.input || teRecord.parameters || teRecord.args || {}; // Extract input from nested toolCall if available if (Object.keys(input).length === 0 && teRecord.toolCall && typeof teRecord.toolCall === "object") { const toolCall = teRecord.toolCall; input = toolCall.input || toolCall.parameters || toolCall.args || {}; } // Enhanced output extraction with success indication let output = teRecord.output || teRecord.result || teRecord.response || "success"; // Enhanced duration extraction let duration = teRecord.duration ?? teRecord.executionTime ?? teRecord.responseTime ?? 0; return { name: toolName, input: input, output: output, duration: duration, }; }); } /** * Transform tool execution results from AI SDK format to internal format (for MCP generation) * Used in tryMCPGeneration method */ export function transformToolExecutionsForMCP(toolExecutions) { if (!toolExecutions || !Array.isArray(toolExecutions)) { return []; } return toolExecutions.map((te, index) => { const teRecord = te; // Enhanced tool name extraction matching the main function let toolName = teRecord.name || teRecord.toolName || teRecord.tool || ""; // Try nested toolCall extraction if (!toolName && teRecord.toolCall && typeof teRecord.toolCall === "object") { const toolCall = teRecord.toolCall; toolName = toolCall.name || toolCall.toolName || ""; } // Fallback to avoid empty names if (!toolName) { toolName = `mcp_tool_execution_${index}`; } // Enhanced execution time extraction let executionTime = teRecord.duration ?? teRecord.executionTime ?? teRecord.responseTime ?? 0; // Enhanced success detection - check for actual success indicators let success = true; // Default to true // Check for explicit success/error indicators if (teRecord.success !== undefined) { success = Boolean(teRecord.success); } else if (teRecord.error !== undefined) { success = false; } else if (teRecord.status !== undefined) { const status = String(teRecord.status).toLowerCase().trim(); success = !["error", "failed", "failure", "fail"].includes(status); } // Enhanced server ID extraction let serverId = teRecord.serverId || teRecord.server || teRecord.source || undefined; // Try to extract from nested structures if (!serverId && teRecord.toolCall && typeof teRecord.toolCall === "object") { const toolCall = teRecord.toolCall; serverId = toolCall.serverId || toolCall.server || undefined; } return { toolName: toolName, executionTime: executionTime, success: success, serverId: serverId, }; }); } // ============================================================================ // AVAILABLE TOOLS TRANSFORMATIONS // ============================================================================ /** * Transform available tools from internal format to GenerateResult format * Ensures consistent tool information structure across the API with schema normalization * * @param availableTools - Array of tool definitions from various sources (MCP servers, builtin tools, etc.) * @returns Array of normalized tool descriptions with consistent schema format * * @example * ```typescript * const tools = transformAvailableTools([ * { name: "calculator", description: "Math tool", server: "builtin", inputSchema: {...} } * ]); * // Returns: [{ name: "calculator", description: "Math tool", serverId: "builtin", schema: {...} }] * ``` */ export function transformAvailableTools(availableTools) { if (!availableTools || !Array.isArray(availableTools)) { return []; } return availableTools.map((tool) => { const toolRecord = tool; return { name: tool.name || "", description: tool.description || "", server: tool.server || "", parameters: toolRecord.inputSchema || toolRecord.parameters || toolRecord.schema || {}, }; }); } /** * Transform tools for MCP generation format * Simple transformation for internal MCP tool lists */ export function transformToolsForMCP(availableTools) { return availableTools.map((tool) => ({ name: tool.name, description: tool.description, server: tool.server, category: tool.category, })); } /** * Transform tools to expected format with required properties * Used in getAllAvailableTools method for final output */ export function transformToolsToExpectedFormat(tools) { return tools.map((tool) => ({ name: tool.name, description: tool.description || "No description available", server: tool.serverId || "unknown", category: tool.category, inputSchema: tool.inputSchema, })); } // ============================================================================ // STRING AND ARRAY TRANSFORMATIONS // ============================================================================ /** * Extract tool names from tool objects * Common pattern for creating arrays of tool names */ export function extractToolNames(tools) { return tools.map((tool) => tool.name); } /** * Extract object keys as a comma-separated string * Common pattern for logging and debugging */ export function getKeysAsString(obj, fallback = "none") { const keys = Object.keys(obj); return keys.length > 0 ? keys.join(", ") : fallback; } /** * Count object properties * Common pattern for metrics and logging */ export function getKeyCount(obj) { return Object.keys(obj).length; } // ============================================================================ // SCHEMA TRANSFORMATIONS // ============================================================================ /** * Transform schema properties to parameter descriptions * Used in tool-aware system prompt generation */ export function transformSchemaToParameterDescription(schema) { if (!schema?.properties) { return ""; } const requiredParams = new Set(schema.required || []); return Object.entries(schema.properties) .map(([key, value]) => { const typedValue = value; const required = requiredParams.has(key) ? " (required)" : ""; return ` - ${key}: ${typedValue.type || "unknown"}${required}`; }) .join("\n"); } /** * Transform tools to tool descriptions for system prompts * Consolidated pattern for creating tool-aware prompts */ export function transformToolsToDescriptions(availableTools) { return availableTools .map((tool) => { const schema = tool.inputSchema; let params = ""; if (schema?.properties) { params = transformSchemaToParameterDescription(schema); } return `- ${tool.name}: ${tool.description} (from ${tool.server})\n${params}`; }) .join("\n\n"); } // ============================================================================ // VALIDATION TRANSFORMATIONS // ============================================================================ /** * Transform parameters for validation * Common pattern when logging or checking parameter structures */ export function transformParamsForLogging(params) { if (!params || typeof params !== "object") { return String(params); } const record = params; return `${Object.keys(record).length} params`; } /** * Safe property extraction from unknown objects * Common pattern for safely accessing properties from unknown structures */ export function safeExtractProperty(obj, key, fallback) { if (!obj || typeof obj !== "object" || obj === null) { return fallback; } const record = obj; const value = record[key]; return value !== undefined ? value : fallback; } /** * Safe extraction of string properties * Specialized version for string properties with fallback */ export function safeExtractString(obj, key, fallback = "") { const value = safeExtractProperty(obj, key, fallback); return typeof value === "string" ? value : fallback; } /** * Safe extraction of number properties * Specialized version for number properties with fallback */ export function safeExtractNumber(obj, key, fallback = 0) { const value = safeExtractProperty(obj, key, fallback); return typeof value === "number" ? value : fallback; } /** * Safe extraction of boolean properties * Specialized version for boolean properties with fallback */ export function safeExtractBoolean(obj, key, fallback = false) { const value = safeExtractProperty(obj, key, fallback); return typeof value === "boolean" ? value : fallback; } // ============================================================================ // COLLECTION TRANSFORMATIONS // ============================================================================ /** * Transform Map to array of values * Common pattern for converting tool maps to arrays */ export function mapToArray(map) { return Array.from(map.values()); } /** * Transform Map to array of key-value pairs * Common pattern for processing map entries */ export function mapToEntries(map) { return Array.from(map.entries()); } /** * Group array items by a key * Common pattern for organizing tools or other objects by category */ export function groupBy(items, keyFn) { const groups = new Map(); for (const item of items) { const key = keyFn(item); const existing = groups.get(key) || []; existing.push(item); groups.set(key, existing); } return groups; } /** * Remove undefined properties from objects * Common pattern for cleaning up object structures */ export function removeUndefinedProperties(obj) { const cleaned = {}; for (const [key, value] of Object.entries(obj)) { if (value !== undefined) { cleaned[key] = value; } } return cleaned; } /** * Merge objects with undefined handling * Common pattern for combining configuration objects */ export function mergeWithUndefinedHandling(target, ...sources) { const result = { ...target }; for (const source of sources) { for (const [key, value] of Object.entries(source)) { if (value !== undefined) { result[key] = value; } } } return result; } // ============================================================================ // TOOL OPTIMIZATION UTILITIES // ============================================================================ /** * Optimize tool information for collection with minimal object creation * Consolidates repeated optimization patterns across different tool sources * * @param tool - Tool information to optimize * @param defaults - Default values to apply if missing * @returns Optimized tool with minimal object creation * * @example * ```typescript * const optimized = optimizeToolForCollection(tool, { * serverId: "builtin", * category: "math" * }); * ``` */ export function optimizeToolForCollection(tool, defaults) { // Check what properties actually need modification const needsDescription = !tool.description && defaults.description; const needsServerId = !tool.serverId && defaults.serverId; const needsCategory = !tool.category && defaults.category; const needsInputSchema = !tool.inputSchema && defaults.inputSchema; const hasParametersConflict = tool.inputSchema && "parameters" in tool; // Only create new object if modifications are actually needed if (!needsDescription && !needsServerId && !needsCategory && !needsInputSchema && !hasParametersConflict) { return tool; // Return original tool without modification } // Create optimized tool with only necessary changes const optimizedTool = { ...tool, ...(needsDescription && { description: defaults.description }), ...(needsServerId && { serverId: defaults.serverId }), ...(needsCategory && { category: defaults.category }), ...(needsInputSchema && { inputSchema: defaults.inputSchema }), }; // Clean up schema conflicts if present if (hasParametersConflict) { const cleanedTool = { ...optimizedTool }; delete cleanedTool.parameters; return cleanedTool; } return optimizedTool; }