UNPKG

anon-identity

Version:

Decentralized identity framework with DIDs, Verifiable Credentials, and privacy-preserving selective disclosure

482 lines 16.3 kB
"use strict"; /** * Function Adapter for MCP * * Converts between different provider function calling formats */ Object.defineProperty(exports, "__esModule", { value: true }); exports.FunctionAdapter = void 0; const types_1 = require("../types"); /** * Function Adapter */ class FunctionAdapter { constructor(config = { strictValidation: true, preserveMetadata: true, sanitizeArguments: true, maxArgumentSize: 10000 // 10KB }) { this.config = config; } /** * Convert MCP function definition to provider format */ toProviderFormat(definition, providerType) { switch (providerType) { case 'openai': return this.toOpenAIFormat(definition); case 'anthropic': return this.toAnthropicFormat(definition); case 'google': return this.toGoogleFormat(definition); default: return definition; } } /** * Convert provider function call to MCP format */ fromProviderCall(providerCall, providerType) { switch (providerType) { case 'openai': return this.fromOpenAICall(providerCall); case 'anthropic': return this.fromAnthropicCall(providerCall); case 'google': return this.fromGoogleCall(providerCall); default: return providerCall; } } /** * Convert provider format to MCP function definition */ fromProviderFormat(providerFunction, providerType) { switch (providerType) { case 'openai': return this.fromOpenAIFormat(providerFunction); case 'anthropic': return this.fromAnthropicFormat(providerFunction); case 'google': return this.fromGoogleFormat(providerFunction); default: return providerFunction; } } /** * Batch convert function definitions */ batchToProviderFormat(definitions, providerType) { return definitions.map(def => this.toProviderFormat(def, providerType)); } /** * Convert to OpenAI format */ toOpenAIFormat(definition) { const openaiFunction = { name: definition.name, description: definition.description, parameters: { type: 'object', properties: this.convertParameters(definition.parameters.properties, 'openai'), required: definition.parameters.required } }; // Validate against OpenAI constraints if (this.config.strictValidation) { this.validateOpenAIFunction(openaiFunction); } return openaiFunction; } /** * Convert from OpenAI format */ fromOpenAIFormat(openaiFunction) { return { name: openaiFunction.name, description: openaiFunction.description, parameters: { type: 'object', properties: this.convertParameters(openaiFunction.parameters.properties, 'generic'), required: openaiFunction.parameters.required || [] } }; } /** * Convert from OpenAI function call */ fromOpenAICall(openaiCall) { let args = {}; try { args = JSON.parse(openaiCall.arguments); } catch (error) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_FUNCTION_CALL, message: `Invalid function arguments: ${error.message}`, timestamp: new Date(), retryable: false }); } if (this.config.sanitizeArguments) { args = this.sanitizeArguments(args); } return { name: openaiCall.name, arguments: args, id: `openai-${Date.now()}` }; } /** * Convert to Anthropic format */ toAnthropicFormat(definition) { return { name: definition.name, description: definition.description, input_schema: { type: 'object', properties: this.convertParameters(definition.parameters.properties, 'anthropic'), required: definition.parameters.required } }; } /** * Convert from Anthropic format */ fromAnthropicFormat(anthropicTool) { return { name: anthropicTool.name, description: anthropicTool.description, parameters: { type: 'object', properties: this.convertParameters(anthropicTool.input_schema.properties, 'generic'), required: anthropicTool.input_schema.required || [] } }; } /** * Convert from Anthropic tool use */ fromAnthropicCall(anthropicCall) { let args = anthropicCall.input; if (this.config.sanitizeArguments) { args = this.sanitizeArguments(args); } return { name: anthropicCall.name, arguments: args, id: anthropicCall.id }; } /** * Convert to Google format */ toGoogleFormat(definition) { return { name: definition.name, description: definition.description, parameters: { type: 'object', properties: this.convertParameters(definition.parameters.properties, 'google'), required: definition.parameters.required } }; } /** * Convert from Google format */ fromGoogleFormat(googleFunction) { return { name: googleFunction.name, description: googleFunction.description, parameters: { type: 'object', properties: this.convertParameters(googleFunction.parameters.properties, 'generic'), required: googleFunction.parameters.required || [] } }; } /** * Convert from Google function call */ fromGoogleCall(googleCall) { let args = googleCall.args || googleCall.arguments || {}; if (this.config.sanitizeArguments) { args = this.sanitizeArguments(args); } return { name: googleCall.name, arguments: args, id: googleCall.id || `google-${Date.now()}` }; } /** * Convert parameter definitions between formats */ convertParameters(properties, targetFormat) { const converted = {}; for (const [name, param] of Object.entries(properties)) { converted[name] = this.convertSingleParameter(param, targetFormat); } return converted; } /** * Convert single parameter definition */ convertSingleParameter(param, targetFormat) { const baseParam = { type: param.type, description: param.description || '' }; // Add common properties if (param.enum) baseParam.enum = param.enum; if (param.default !== undefined) baseParam.default = param.default; // Type-specific properties switch (param.type) { case 'string': if (param.minLength !== undefined) baseParam.minLength = param.minLength; if (param.maxLength !== undefined) baseParam.maxLength = param.maxLength; if (param.pattern) baseParam.pattern = param.pattern; break; case 'number': case 'integer': if (param.minimum !== undefined) baseParam.minimum = param.minimum; if (param.maximum !== undefined) baseParam.maximum = param.maximum; if (param.multipleOf !== undefined) baseParam.multipleOf = param.multipleOf; break; case 'array': if (param.items) { baseParam.items = this.convertSingleParameter(param.items, targetFormat); } if (param.minItems !== undefined) baseParam.minItems = param.minItems; if (param.maxItems !== undefined) baseParam.maxItems = param.maxItems; break; case 'object': if (param.properties) { baseParam.properties = this.convertParameters(param.properties, targetFormat); } if (param.required) baseParam.required = param.required; if (param.additionalProperties !== undefined) { baseParam.additionalProperties = param.additionalProperties; } break; } // Provider-specific adjustments switch (targetFormat) { case 'openai': // OpenAI doesn't support some JSON Schema features delete baseParam.multipleOf; break; case 'anthropic': // Anthropic uses slightly different naming if (baseParam.enum) { baseParam.enum = baseParam.enum; } break; case 'google': // Google has its own constraints break; } return baseParam; } /** * Validate OpenAI function */ validateOpenAIFunction(func) { // Check name constraints if (!/^[a-zA-Z0-9_-]{1,64}$/.test(func.name)) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_FUNCTION_CALL, message: 'OpenAI function names must be 1-64 characters, alphanumeric plus underscore and dash', timestamp: new Date(), retryable: false }); } // Check description length if (func.description.length > 1024) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_FUNCTION_CALL, message: 'OpenAI function description must be <= 1024 characters', timestamp: new Date(), retryable: false }); } // Check parameters structure this.validateParametersStructure(func.parameters); } /** * Validate parameters structure */ validateParametersStructure(params) { if (params.type !== 'object') { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_FUNCTION_CALL, message: 'Function parameters must be of type "object"', timestamp: new Date(), retryable: false }); } if (!params.properties || typeof params.properties !== 'object') { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_FUNCTION_CALL, message: 'Function parameters must have properties', timestamp: new Date(), retryable: false }); } // Recursively validate nested objects for (const [name, prop] of Object.entries(params.properties)) { if (typeof prop === 'object' && prop !== null && 'type' in prop && prop.type === 'object' && 'properties' in prop && prop.properties) { this.validateParametersStructure(prop); } } } /** * Sanitize function arguments */ sanitizeArguments(args) { const sanitized = {}; for (const [key, value] of Object.entries(args)) { // Check key safety if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)) { continue; // Skip unsafe keys } // Sanitize value sanitized[key] = this.sanitizeValue(value); } return sanitized; } /** * Sanitize individual value */ sanitizeValue(value) { if (value === null || value === undefined) { return value; } if (typeof value === 'string') { // Limit string length if (value.length > this.config.maxArgumentSize) { return value.substring(0, this.config.maxArgumentSize); } return value; } if (typeof value === 'number' || typeof value === 'boolean') { return value; } if (Array.isArray(value)) { return value.slice(0, 100).map(item => this.sanitizeValue(item)); // Limit array size } if (typeof value === 'object') { const sanitized = {}; let keyCount = 0; for (const [key, val] of Object.entries(value)) { if (keyCount >= 100) break; // Limit object size if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)) continue; // Skip unsafe keys sanitized[key] = this.sanitizeValue(val); keyCount++; } return sanitized; } return null; // Drop unknown types } /** * Get supported provider types */ getSupportedProviders() { return ['openai', 'anthropic', 'google', 'generic']; } /** * Check if provider supports feature */ supportsFeature(providerType, feature) { const supportMatrix = { openai: { function_calling: true, streaming_functions: true, parallel_functions: true, nested_objects: true, arrays: true, enums: true }, anthropic: { function_calling: true, streaming_functions: false, parallel_functions: false, nested_objects: true, arrays: true, enums: true }, google: { function_calling: true, streaming_functions: true, parallel_functions: true, nested_objects: true, arrays: true, enums: true }, generic: { function_calling: true, streaming_functions: true, parallel_functions: true, nested_objects: true, arrays: true, enums: true } }; return supportMatrix[providerType]?.[feature] || false; } /** * Get provider constraints */ getProviderConstraints(providerType) { const constraints = { openai: { maxFunctionNameLength: 64, maxDescriptionLength: 1024, maxParameters: 100, maxNestingDepth: 5, supportedTypes: ['string', 'number', 'integer', 'boolean', 'array', 'object'] }, anthropic: { maxFunctionNameLength: 64, maxDescriptionLength: 2048, maxParameters: 100, maxNestingDepth: 10, supportedTypes: ['string', 'number', 'integer', 'boolean', 'array', 'object'] }, google: { maxFunctionNameLength: 64, maxDescriptionLength: 1024, maxParameters: 50, maxNestingDepth: 5, supportedTypes: ['string', 'number', 'integer', 'boolean', 'array', 'object'] }, generic: { maxFunctionNameLength: 128, maxDescriptionLength: 4096, maxParameters: 200, maxNestingDepth: 20, supportedTypes: ['string', 'number', 'integer', 'boolean', 'array', 'object', 'null'] } }; return constraints[providerType] || constraints.generic; } } exports.FunctionAdapter = FunctionAdapter; exports.default = FunctionAdapter; //# sourceMappingURL=function-adapter.js.map