Skip to main content
Glama
moduleSelection.ts13.1 kB
/** * Dedicated Zod schemas for Module Selection in Fullstack Starter Kit Generator * * These schemas define the exact structure expected from LLM responses * for module selection and template generation, enabling precise validation * and better prompt engineering. */ import { z } from 'zod'; /** * Schema for module parameters used in template substitution */ export const moduleParametersSchema = z.record(z.union([ z.string(), z.number(), z.boolean() ])).describe('Key-value pairs for template parameter substitution'); /** * Schema for individual module selection */ export const moduleSelectionItemSchema = z.object({ modulePath: z.string() .min(1, 'Module path cannot be empty') .describe('Path to the module template (e.g., "frontend/react-vite", "backend/nodejs-express")'), params: moduleParametersSchema .describe('Parameters for template substitution specific to this module'), moduleKey: z.string() .optional() .describe('Optional key for path resolution (e.g., "frontend", "backend")') }).describe('Configuration for a single module to be included in the starter kit'); /** * Enhanced module selection item schema with module type support */ export const enhancedModuleSelectionItemSchema = z.object({ modulePath: z.string() .min(1, 'Module path cannot be empty') .describe('Path to the module template (e.g., "ai-integration/openai-langchain", "development-tools/monaco-judge0")'), moduleType: z.string() .min(1, 'Module type cannot be empty') .describe('Type/category of the module (e.g., "ai-integration", "development-tools", "real-time", "payment")'), params: moduleParametersSchema .describe('Parameters for template substitution specific to this module'), moduleKey: z.string() .optional() .describe('Optional key for path resolution (e.g., "frontend", "backend", "root")') }).describe('Enhanced configuration for a single module with type classification'); /** * Schema for global parameters that apply to the entire project */ export const globalParametersSchema = z.object({ projectName: z.string() .min(1, 'Project name is required') .max(100, 'Project name must be 100 characters or less') .regex(/^[a-zA-Z0-9\s\-_]+$/, 'Project name can only contain letters, numbers, spaces, hyphens, and underscores') .describe('The name of the project being generated'), projectDescription: z.string() .min(10, 'Project description must be at least 10 characters') .max(500, 'Project description must be 500 characters or less') .describe('A brief description of what the project does'), frontendPath: z.string() .describe('Directory path for frontend code (default: "client")'), backendPath: z.string() .describe('Directory path for backend code (default: "server")'), backendPort: z.number() .int() .min(1000, 'Port must be at least 1000') .max(65535, 'Port must be at most 65535') .describe('Port number for the backend server (default: 3000)'), databaseName: z.string() .optional() .describe('Name of the database (if applicable)'), apiPrefix: z.string() .describe('API route prefix (default: "/api")'), enableTypeScript: z.boolean() .describe('Whether to use TypeScript (default: true)'), enableTesting: z.boolean() .describe('Whether to include testing setup (default: true)'), enableDocker: z.boolean() .describe('Whether to include Docker configuration (default: false)'), enableCICD: z.boolean() .describe('Whether to include CI/CD configuration (default: false)') }).describe('Global parameters that apply to the entire project configuration'); /** * Main schema for module selection response from LLM */ export const moduleSelectionResponseSchema = z.object({ globalParams: globalParametersSchema .describe('Global parameters that apply to the entire project'), moduleSelections: z.array(moduleSelectionItemSchema) .min(1, 'At least one module must be selected') .max(10, 'Cannot select more than 10 modules') .describe('Array of modules to be included in the starter kit') }).describe('Complete module selection configuration for generating a fullstack starter kit'); /** * Schema for dynamic template generation response * Updated to match the actual structure expected by the system and generated by LLMs */ export const dynamicTemplateSchema = z.object({ moduleName: z.string() .min(1, 'Module name is required') .describe('Unique identifier for this module'), description: z.string() .min(10, 'Description must be at least 10 characters') .describe('Brief description of what this module provides'), type: z.string() .min(1, 'Module type is required') .describe('Category/type of the module (e.g., frontend, backend, database, fullstack, utility, monitoring, etc.)'), placeholders: z.array(z.string()) .optional() .describe('List of placeholder variables used in this template'), provides: z.object({ techStack: z.record(z.object({ name: z.string().describe('Technology name'), version: z.string().optional().describe('Version specification'), rationale: z.string().optional().describe('Why this technology was chosen') })).optional().describe('Technologies provided by this module'), directoryStructure: z.array(z.object({ path: z.string().min(1, "Path cannot be empty").describe('File or directory path'), type: z.enum(['file', 'directory']).describe('Whether this is a file or directory'), content: z.string().nullable().describe('File content (null for directories, string for files)'), generationPrompt: z.string().nullable().optional().describe('Prompt for generating file content'), children: z.array(z.any()).optional().describe('Child items (for directories only)') })).optional().describe('Directory structure created by this module'), dependencies: z.object({ npm: z.record(z.object({ dependencies: z.record(z.string()).optional(), devDependencies: z.record(z.string()).optional() })).optional() }).optional().describe('Package dependencies added by this module'), setupCommands: z.array(z.object({ command: z.string().describe('Command to execute'), context: z.string().optional().describe('Context or explanation for the command') })).optional().describe('Commands to run during setup with context'), nextSteps: z.array(z.string()) .optional() .describe('Recommended next steps after using this module') }).describe('What this module provides to the project') }).describe('Dynamically generated module template structure'); /** * Enhanced module selection response schema for research-driven dynamic generation * Supports more complex projects with increased module limits and type classification */ export const enhancedModuleSelectionResponseSchema = z.object({ globalParams: globalParametersSchema .describe('Global parameters that apply to the entire project'), moduleSelections: z.array(enhancedModuleSelectionItemSchema) .min(1, 'At least one module must be selected') .max(15, 'Maximum 15 modules allowed for complex projects') .describe('Array of selected modules with their configurations and types') }).describe('Enhanced response schema for complex module selection with research context'); /** * Unified template schema for dynamic template generation * Supports comprehensive module definitions with research-enhanced context */ export const unifiedTemplateSchema = z.object({ moduleName: z.string() .min(1, 'Module name is required') .describe('Unique identifier for this module'), description: z.string() .min(10, 'Description must be at least 10 characters') .describe('Brief description of what this module provides'), type: z.string() .min(1, 'Module type is required') .describe('Category/type of the module (e.g., ai-integration, development-tools, real-time)'), provides: z.object({ techStack: z.record(z.object({ name: z.string().describe('Technology name'), version: z.string().optional().describe('Version specification'), rationale: z.string().describe('Why this technology was chosen based on research') })).optional().describe('Technologies provided by this module'), directoryStructure: z.array(z.object({ path: z.string().min(1, "Path cannot be empty").describe('File or directory path'), type: z.enum(['file', 'directory']).describe('Whether this is a file or directory'), content: z.string().nullable().describe('File content (null for directories)'), generationPrompt: z.string().nullable().optional().describe('Prompt for generating file content'), children: z.array(z.any()).optional().describe('Child items (for directories only)') })).optional().describe('Directory structure created by this module'), setupCommands: z.array(z.object({ command: z.string().describe('Command to execute'), context: z.string().optional().describe('Context or explanation for the command') })).optional().describe('Commands to run during setup with context') }).describe('What this module provides to the project') }).describe('Unified template schema for research-enhanced dynamic generation'); // Export TypeScript types for use in the application export type ModuleParameters = z.infer<typeof moduleParametersSchema>; export type ModuleSelectionItem = z.infer<typeof moduleSelectionItemSchema>; export type EnhancedModuleSelectionItem = z.infer<typeof enhancedModuleSelectionItemSchema>; export type GlobalParameters = z.infer<typeof globalParametersSchema>; export type ModuleSelectionResponse = z.infer<typeof moduleSelectionResponseSchema>; export type EnhancedModuleSelectionResponse = z.infer<typeof enhancedModuleSelectionResponseSchema>; export type DynamicTemplate = z.infer<typeof dynamicTemplateSchema>; export type UnifiedTemplate = z.infer<typeof unifiedTemplateSchema>; /** * Validation helper functions */ export function validateModuleSelectionResponse(data: unknown): data is ModuleSelectionResponse { try { moduleSelectionResponseSchema.parse(data); return true; } catch { return false; } } export function validateDynamicTemplate(data: unknown): data is DynamicTemplate { try { dynamicTemplateSchema.parse(data); return true; } catch { return false; } } export function validateEnhancedModuleSelectionResponse(data: unknown): data is EnhancedModuleSelectionResponse { try { enhancedModuleSelectionResponseSchema.parse(data); return true; } catch { return false; } } export function validateUnifiedTemplate(data: unknown): data is UnifiedTemplate { try { unifiedTemplateSchema.parse(data); return true; } catch { return false; } } /** * Schema validation with detailed error messages */ export function validateModuleSelectionWithErrors(data: unknown): { success: boolean; data?: ModuleSelectionResponse; errors?: string[]; } { try { const validated = moduleSelectionResponseSchema.parse(data); return { success: true, data: validated }; } catch (error) { if (error instanceof z.ZodError) { const errors = error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}` ); return { success: false, errors }; } return { success: false, errors: ['Unknown validation error'] }; } } export function validateDynamicTemplateWithErrors(data: unknown): { success: boolean; data?: DynamicTemplate; errors?: string[]; } { try { const validated = dynamicTemplateSchema.parse(data); return { success: true, data: validated }; } catch (error) { if (error instanceof z.ZodError) { const errors = error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}` ); return { success: false, errors }; } return { success: false, errors: ['Unknown validation error'] }; } } export function validateEnhancedModuleSelectionWithErrors(data: unknown): { success: boolean; data?: EnhancedModuleSelectionResponse; errors?: string[]; } { try { const validated = enhancedModuleSelectionResponseSchema.parse(data); return { success: true, data: validated }; } catch (error) { if (error instanceof z.ZodError) { const errors = error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}` ); return { success: false, errors }; } return { success: false, errors: ['Unknown validation error'] }; } } export function validateUnifiedTemplateWithErrors(data: unknown): { success: boolean; data?: UnifiedTemplate; errors?: string[]; } { try { const validated = unifiedTemplateSchema.parse(data); return { success: true, data: validated }; } catch (error) { if (error instanceof z.ZodError) { const errors = error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}` ); return { success: false, errors }; } return { success: false, errors: ['Unknown validation error'] }; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/freshtechbro/vibe-coder-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server