UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

294 lines (293 loc) 11.5 kB
// src/lib/action/actionInputs.ts /** * GitHub Action input parsing and validation * @module action/actionInputs */ import * as core from "@actions/core"; import { AIProviderName } from "../constants/enums.js"; import { ErrorFactory } from "../utils/errorHandling.js"; const PROVIDER_KEY_MAP = { [AIProviderName.OPENAI]: ["openaiApiKey"], [AIProviderName.ANTHROPIC]: ["anthropicApiKey"], [AIProviderName.GOOGLE_AI]: ["googleAiApiKey"], [AIProviderName.VERTEX]: ["googleVertexProject"], [AIProviderName.BEDROCK]: ["awsAccessKeyId", "awsSecretAccessKey"], [AIProviderName.AZURE]: ["azureOpenaiApiKey", "azureOpenaiEndpoint"], [AIProviderName.MISTRAL]: ["mistralApiKey"], [AIProviderName.HUGGINGFACE]: ["huggingfaceApiKey"], [AIProviderName.OPENROUTER]: ["openrouterApiKey"], [AIProviderName.LITELLM]: ["litellmApiKey", "litellmBaseUrl"], [AIProviderName.SAGEMAKER]: ["awsAccessKeyId", "awsSecretAccessKey"], [AIProviderName.OPENAI_COMPATIBLE]: [ "openaiCompatibleApiKey", "openaiCompatibleBaseUrl", ], }; /** * Parse comma-separated paths into array */ function parsePathList(input) { if (!input) { return undefined; } return input .split(",") .map((p) => p.trim()) .filter(Boolean); } /** * Parse and validate a numeric input, throwing if NaN */ function parseNumericInput(inputName, rawValue, defaultValue, parseFunction, radix) { if (!rawValue) { return defaultValue; } const parsed = radix !== undefined ? parseFunction(rawValue, radix) : parseFunction(rawValue); if (isNaN(parsed)) { throw ErrorFactory.invalidConfiguration(inputName, `expected a valid number but received "${rawValue}"`); } return parsed; } /** * Mask all secrets in logs */ export function maskSecrets(inputs) { const secrets = [ inputs.providerKeys.openaiApiKey, inputs.providerKeys.anthropicApiKey, inputs.providerKeys.googleAiApiKey, inputs.providerKeys.azureOpenaiApiKey, inputs.providerKeys.mistralApiKey, inputs.providerKeys.huggingfaceApiKey, inputs.providerKeys.openrouterApiKey, inputs.providerKeys.litellmApiKey, inputs.providerKeys.openaiCompatibleApiKey, inputs.awsConfig.awsAccessKeyId, inputs.awsConfig.awsSecretAccessKey, inputs.awsConfig.awsSessionToken, inputs.googleCloudConfig.googleApplicationCredentials, inputs.githubToken, ]; secrets .filter((s) => Boolean(s)) .forEach((secret) => core.setSecret(secret)); } /** * Validate that provider has required API key */ export function validateProviderKey(provider, keys, awsConfig, googleConfig) { // These providers don't require API keys if (provider === "auto" || provider === "ollama") { return true; } const requiredKeys = PROVIDER_KEY_MAP[provider]; if (!requiredKeys) { // Log warning for unknown provider, but don't fail (allows new providers) core.warning(`Unknown provider "${provider}" - skipping key validation`); return true; } // Check keys across all config objects return requiredKeys.every((key) => { const keyValue = keys[key] || awsConfig?.[key] || googleConfig?.[key]; return !!keyValue; }); } /** * Parse all action inputs from GitHub Action context */ export function parseActionInputs() { const prompt = core.getInput("prompt", { required: true }); const provider = core.getInput("provider") || "auto"; // Parse provider keys (verified providers only) const providerKeys = { openaiApiKey: core.getInput("openai_api_key") || undefined, anthropicApiKey: core.getInput("anthropic_api_key") || undefined, googleAiApiKey: core.getInput("google_ai_api_key") || undefined, azureOpenaiApiKey: core.getInput("azure_openai_api_key") || undefined, azureOpenaiEndpoint: core.getInput("azure_openai_endpoint") || undefined, azureOpenaiDeployment: core.getInput("azure_openai_deployment") || undefined, mistralApiKey: core.getInput("mistral_api_key") || undefined, huggingfaceApiKey: core.getInput("huggingface_api_key") || undefined, openrouterApiKey: core.getInput("openrouter_api_key") || undefined, litellmApiKey: core.getInput("litellm_api_key") || undefined, litellmBaseUrl: core.getInput("litellm_base_url") || undefined, openaiCompatibleApiKey: core.getInput("openai_compatible_api_key") || undefined, openaiCompatibleBaseUrl: core.getInput("openai_compatible_base_url") || undefined, }; // AWS config const awsConfig = { awsAccessKeyId: core.getInput("aws_access_key_id") || undefined, awsSecretAccessKey: core.getInput("aws_secret_access_key") || undefined, awsRegion: core.getInput("aws_region") || "us-east-1", awsSessionToken: core.getInput("aws_session_token") || undefined, bedrockModelId: core.getInput("bedrock_model_id") || undefined, sagemakerEndpoint: core.getInput("sagemaker_endpoint") || undefined, }; // Google Cloud config const googleCloudConfig = { googleVertexProject: core.getInput("google_vertex_project") || undefined, googleVertexLocation: core.getInput("google_vertex_location") || "us-central1", googleApplicationCredentials: core.getInput("google_application_credentials") || undefined, }; // Validate provider has key if (!validateProviderKey(provider, providerKeys, awsConfig, googleCloudConfig)) { throw ErrorFactory.missingConfiguration(`API key for provider: ${provider}`); } return { prompt, provider: provider, model: core.getInput("model") || undefined, // Generation parameters temperature: parseNumericInput("temperature", core.getInput("temperature"), 0.7, parseFloat), maxTokens: parseNumericInput("max_tokens", core.getInput("max_tokens"), 4096, parseInt, 10), systemPrompt: core.getInput("system_prompt") || undefined, // Command command: (core.getInput("command") || "generate"), // Provider keys providerKeys, // AWS config awsConfig, // Google Cloud config googleCloudConfig, // Multimodal inputs multimodal: { imagePaths: parsePathList(core.getInput("image_paths")), pdfPaths: parsePathList(core.getInput("pdf_paths")), csvPaths: parsePathList(core.getInput("csv_paths")), videoPaths: parsePathList(core.getInput("video_paths")), }, // Extended thinking thinking: { enabled: core.getBooleanInput("thinking_enabled"), level: (core.getInput("thinking_level") || "medium"), budget: parseNumericInput("thinking_budget", core.getInput("thinking_budget"), 10000, parseInt, 10), }, // Features (verified to exist in CLI) enableAnalytics: core.getBooleanInput("enable_analytics"), enableEvaluation: core.getBooleanInput("enable_evaluation"), // Output outputFormat: (core.getInput("output_format") || "text"), outputFile: core.getInput("output_file") || undefined, // MCP Tools enableTools: core.getBooleanInput("enable_tools"), mcpConfigPath: core.getInput("mcp_config_path") || undefined, // GitHub Integration postComment: core.getBooleanInput("post_comment"), updateExistingComment: core.getBooleanInput("update_existing_comment"), commentTag: core.getInput("comment_tag") || "neurolink-action", githubToken: core.getInput("github_token") || process.env.GITHUB_TOKEN, // Advanced timeout: parseNumericInput("timeout", core.getInput("timeout"), 300, parseInt, 10), debug: core.getBooleanInput("debug"), neurolinkVersion: core.getInput("neurolink_version") || "latest", workingDirectory: core.getInput("working_directory") || ".", }; } /** * Build environment variables from action inputs */ export function buildEnvironmentVariables(inputs) { const env = { CI: "true", NEUROLINK_NON_INTERACTIVE: "true", }; // Provider keys const { providerKeys } = inputs; if (providerKeys.openaiApiKey) { env.OPENAI_API_KEY = providerKeys.openaiApiKey; } if (providerKeys.anthropicApiKey) { env.ANTHROPIC_API_KEY = providerKeys.anthropicApiKey; } if (providerKeys.googleAiApiKey) { env.GOOGLE_AI_API_KEY = providerKeys.googleAiApiKey; } if (providerKeys.azureOpenaiApiKey) { env.AZURE_OPENAI_API_KEY = providerKeys.azureOpenaiApiKey; } if (providerKeys.azureOpenaiEndpoint) { env.AZURE_OPENAI_ENDPOINT = providerKeys.azureOpenaiEndpoint; } if (providerKeys.azureOpenaiDeployment) { env.AZURE_OPENAI_DEPLOYMENT = providerKeys.azureOpenaiDeployment; } if (providerKeys.mistralApiKey) { env.MISTRAL_API_KEY = providerKeys.mistralApiKey; } if (providerKeys.huggingfaceApiKey) { env.HUGGINGFACE_API_KEY = providerKeys.huggingfaceApiKey; } if (providerKeys.openrouterApiKey) { env.OPENROUTER_API_KEY = providerKeys.openrouterApiKey; } if (providerKeys.litellmApiKey) { env.LITELLM_API_KEY = providerKeys.litellmApiKey; } if (providerKeys.litellmBaseUrl) { env.LITELLM_BASE_URL = providerKeys.litellmBaseUrl; } if (providerKeys.openaiCompatibleApiKey) { env.OPENAI_COMPATIBLE_API_KEY = providerKeys.openaiCompatibleApiKey; } if (providerKeys.openaiCompatibleBaseUrl) { env.OPENAI_COMPATIBLE_BASE_URL = providerKeys.openaiCompatibleBaseUrl; } // AWS const { awsConfig } = inputs; if (awsConfig.awsAccessKeyId) { env.AWS_ACCESS_KEY_ID = awsConfig.awsAccessKeyId; } if (awsConfig.awsSecretAccessKey) { env.AWS_SECRET_ACCESS_KEY = awsConfig.awsSecretAccessKey; } env.AWS_REGION = awsConfig.awsRegion; if (awsConfig.awsSessionToken) { env.AWS_SESSION_TOKEN = awsConfig.awsSessionToken; } if (awsConfig.bedrockModelId) { env.BEDROCK_MODEL_ID = awsConfig.bedrockModelId; } if (awsConfig.sagemakerEndpoint) { env.SAGEMAKER_DEFAULT_ENDPOINT = awsConfig.sagemakerEndpoint; } // Google Cloud const { googleCloudConfig } = inputs; if (googleCloudConfig.googleVertexProject) { env.GOOGLE_VERTEX_PROJECT = googleCloudConfig.googleVertexProject; } env.GOOGLE_VERTEX_LOCATION = googleCloudConfig.googleVertexLocation; // GitHub if (inputs.githubToken) { env.GITHUB_TOKEN = inputs.githubToken; } return env; } /** * Validate all action inputs */ export function validateActionInputs(inputs) { const errors = []; const warnings = []; // Required fields if (!inputs.prompt) { errors.push("prompt is required"); } // Temperature range if (inputs.temperature < 0 || inputs.temperature > 2) { warnings.push("temperature should be between 0 and 2"); } // Thinking budget range if (inputs.thinking.enabled && (inputs.thinking.budget < 5000 || inputs.thinking.budget > 100000)) { warnings.push("thinking_budget should be between 5000 and 100000"); } return { valid: errors.length === 0, errors, warnings, }; }