azureai-optimizer
Version:
AI-Powered Azure Infrastructure Optimization via Model Context Protocol
244 lines • 9.72 kB
JavaScript
/**
* Error Handling Utilities
* Standardized error types and handling for MCP operations
*/
export var ErrorCode;
(function (ErrorCode) {
// MCP Standard Error Codes
ErrorCode[ErrorCode["PARSE_ERROR"] = -32700] = "PARSE_ERROR";
ErrorCode[ErrorCode["INVALID_REQUEST"] = -32600] = "INVALID_REQUEST";
ErrorCode[ErrorCode["METHOD_NOT_FOUND"] = -32601] = "METHOD_NOT_FOUND";
ErrorCode[ErrorCode["INVALID_PARAMS"] = -32602] = "INVALID_PARAMS";
ErrorCode[ErrorCode["INTERNAL_ERROR"] = -32603] = "INTERNAL_ERROR";
// Custom Error Codes
ErrorCode[ErrorCode["UNAUTHORIZED"] = -32000] = "UNAUTHORIZED";
ErrorCode[ErrorCode["FORBIDDEN"] = -32001] = "FORBIDDEN";
ErrorCode[ErrorCode["NOT_FOUND"] = -32002] = "NOT_FOUND";
ErrorCode[ErrorCode["TIMEOUT"] = -32003] = "TIMEOUT";
ErrorCode[ErrorCode["RATE_LIMITED"] = -32004] = "RATE_LIMITED";
ErrorCode[ErrorCode["SERVICE_UNAVAILABLE"] = -32005] = "SERVICE_UNAVAILABLE";
// Azure-specific Error Codes
ErrorCode[ErrorCode["AZURE_AUTH_FAILED"] = -33000] = "AZURE_AUTH_FAILED";
ErrorCode[ErrorCode["AZURE_SUBSCRIPTION_NOT_FOUND"] = -33001] = "AZURE_SUBSCRIPTION_NOT_FOUND";
ErrorCode[ErrorCode["AZURE_PERMISSION_DENIED"] = -33002] = "AZURE_PERMISSION_DENIED";
ErrorCode[ErrorCode["AZURE_API_ERROR"] = -33003] = "AZURE_API_ERROR";
ErrorCode[ErrorCode["AZURE_QUOTA_EXCEEDED"] = -33004] = "AZURE_QUOTA_EXCEEDED";
// Tool-specific Error Codes
ErrorCode[ErrorCode["TOOL_EXECUTION_FAILED"] = -34000] = "TOOL_EXECUTION_FAILED";
ErrorCode[ErrorCode["TOOL_NOT_FOUND"] = -34001] = "TOOL_NOT_FOUND";
ErrorCode[ErrorCode["TOOL_CONFIGURATION_ERROR"] = -34002] = "TOOL_CONFIGURATION_ERROR";
ErrorCode[ErrorCode["AI_PROVIDER_ERROR"] = -34003] = "AI_PROVIDER_ERROR";
ErrorCode[ErrorCode["DATA_VALIDATION_ERROR"] = -34004] = "DATA_VALIDATION_ERROR";
})(ErrorCode || (ErrorCode = {}));
export class MCPError extends Error {
code;
data;
constructor(code, message, data) {
super(message);
this.name = 'MCPError';
this.code = code;
this.data = data;
// Ensure proper prototype chain
Object.setPrototypeOf(this, MCPError.prototype);
}
toJSON() {
return {
code: this.code,
message: this.message,
data: this.data
};
}
static fromError(error, code = ErrorCode.INTERNAL_ERROR) {
if (error instanceof MCPError) {
return error;
}
const message = error instanceof Error ? error.message : String(error);
const data = error instanceof Error ? { stack: error.stack } : undefined;
return new MCPError(code, message, data);
}
static isRetryable(error) {
const retryableCodes = [
ErrorCode.TIMEOUT,
ErrorCode.RATE_LIMITED,
ErrorCode.SERVICE_UNAVAILABLE,
ErrorCode.AZURE_API_ERROR
];
return retryableCodes.includes(error.code);
}
}
export class AzureError extends MCPError {
azureErrorCode;
requestId;
constructor(code, message, azureErrorCode, requestId, data) {
super(code, message, data);
this.name = 'AzureError';
if (azureErrorCode !== undefined) {
this.azureErrorCode = azureErrorCode;
}
if (requestId !== undefined) {
this.requestId = requestId;
}
}
static fromAzureResponse(response) {
const errorCode = response.error?.code || 'UnknownError';
const message = response.error?.message || 'Unknown Azure error';
const requestId = response.headers?.['x-ms-request-id'];
let mcpCode;
switch (errorCode) {
case 'AuthenticationFailed':
case 'InvalidAuthenticationToken':
mcpCode = ErrorCode.AZURE_AUTH_FAILED;
break;
case 'SubscriptionNotFound':
mcpCode = ErrorCode.AZURE_SUBSCRIPTION_NOT_FOUND;
break;
case 'AuthorizationFailed':
case 'Forbidden':
mcpCode = ErrorCode.AZURE_PERMISSION_DENIED;
break;
case 'QuotaExceeded':
case 'TooManyRequests':
mcpCode = ErrorCode.AZURE_QUOTA_EXCEEDED;
break;
default:
mcpCode = ErrorCode.AZURE_API_ERROR;
}
return new AzureError(mcpCode, message, errorCode, requestId, response);
}
}
export class ToolError extends MCPError {
toolName;
executionContext;
constructor(toolName, code, message, executionContext, data) {
super(code, message, data);
this.name = 'ToolError';
this.toolName = toolName;
this.executionContext = executionContext;
}
static toolNotFound(toolName) {
return new ToolError(toolName, ErrorCode.TOOL_NOT_FOUND, `Tool '${toolName}' not found`);
}
static executionFailed(toolName, error, context) {
const message = error instanceof Error ? error.message : String(error);
return new ToolError(toolName, ErrorCode.TOOL_EXECUTION_FAILED, `Tool '${toolName}' execution failed: ${message}`, context, error);
}
static configurationError(toolName, message) {
return new ToolError(toolName, ErrorCode.TOOL_CONFIGURATION_ERROR, `Tool '${toolName}' configuration error: ${message}`);
}
}
export class ValidationError extends MCPError {
field;
value;
constructor(message, field, value) {
super(ErrorCode.DATA_VALIDATION_ERROR, message, { field, value });
this.name = 'ValidationError';
if (field !== undefined) {
this.field = field;
}
this.value = value;
}
static required(field) {
return new ValidationError(`Field '${field}' is required`, field);
}
static invalid(field, value, reason) {
const message = reason
? `Field '${field}' has invalid value: ${reason}`
: `Field '${field}' has invalid value`;
return new ValidationError(message, field, value);
}
static type(field, expectedType, actualType) {
return new ValidationError(`Field '${field}' must be of type ${expectedType}, got ${actualType}`, field);
}
}
export class AIProviderError extends MCPError {
provider;
originalError;
constructor(provider, message, originalError) {
super(ErrorCode.AI_PROVIDER_ERROR, message, originalError);
this.name = 'AIProviderError';
this.provider = provider;
this.originalError = originalError;
}
static notConfigured(provider) {
return new AIProviderError(provider, `AI provider '${provider}' is not configured`);
}
static apiError(provider, error) {
const message = error instanceof Error ? error.message : String(error);
return new AIProviderError(provider, `AI provider '${provider}' API error: ${message}`, error);
}
static quotaExceeded(provider) {
return new AIProviderError(provider, `AI provider '${provider}' quota exceeded`);
}
}
export function handleError(error) {
// Convert various error types to MCPError
if (error instanceof MCPError) {
return error;
}
if (error instanceof Error) {
// Check for specific error patterns
if (error.message.includes('authentication') || error.message.includes('unauthorized')) {
return new MCPError(ErrorCode.UNAUTHORIZED, error.message);
}
if (error.message.includes('permission') || error.message.includes('forbidden')) {
return new MCPError(ErrorCode.FORBIDDEN, error.message);
}
if (error.message.includes('not found')) {
return new MCPError(ErrorCode.NOT_FOUND, error.message);
}
if (error.message.includes('timeout')) {
return new MCPError(ErrorCode.TIMEOUT, error.message);
}
if (error.message.includes('rate limit')) {
return new MCPError(ErrorCode.RATE_LIMITED, error.message);
}
// Default to internal error
return new MCPError(ErrorCode.INTERNAL_ERROR, error.message, { stack: error.stack });
}
// Handle non-Error objects
return new MCPError(ErrorCode.INTERNAL_ERROR, String(error));
}
export function isRetryableError(error) {
if (error instanceof MCPError) {
return MCPError.isRetryable(error);
}
// Check for common retryable error patterns
const errorMessage = String(error).toLowerCase();
const retryablePatterns = [
'timeout',
'rate limit',
'service unavailable',
'temporary failure',
'connection reset',
'network error'
];
return retryablePatterns.some(pattern => errorMessage.includes(pattern));
}
export function getErrorSeverity(error) {
switch (error.code) {
case ErrorCode.PARSE_ERROR:
case ErrorCode.INVALID_REQUEST:
case ErrorCode.INVALID_PARAMS:
return 'medium';
case ErrorCode.METHOD_NOT_FOUND:
case ErrorCode.NOT_FOUND:
case ErrorCode.TOOL_NOT_FOUND:
return 'low';
case ErrorCode.UNAUTHORIZED:
case ErrorCode.FORBIDDEN:
case ErrorCode.AZURE_AUTH_FAILED:
case ErrorCode.AZURE_PERMISSION_DENIED:
return 'high';
case ErrorCode.INTERNAL_ERROR:
case ErrorCode.AZURE_API_ERROR:
case ErrorCode.TOOL_EXECUTION_FAILED:
return 'critical';
case ErrorCode.TIMEOUT:
case ErrorCode.RATE_LIMITED:
case ErrorCode.SERVICE_UNAVAILABLE:
return 'medium';
default:
return 'medium';
}
}
//# sourceMappingURL=errors.js.map