homeassistant-mcp

import express from 'express'; import { z } from 'zod'; import { NLPProcessor } from '../nlp/processor.js'; import { AIRateLimit, AIContext, AIResponse, AIError, AIModel } from '../types/index.js'; import rateLimit from 'express-rate-limit'; const router = express.Router(); const nlpProcessor = new NLPProcessor(); // Rate limiting configuration const rateLimitConfig: AIRateLimit = { requests_per_minute: 100, requests_per_hour: 1000, concurrent_requests: 10, model_specific_limits: { claude: { requests_per_minute: 100, requests_per_hour: 1000 }, gpt4: { requests_per_minute: 50, requests_per_hour: 500 }, custom: { requests_per_minute: 200, requests_per_hour: 2000 } } }; // Request validation schemas const interpretRequestSchema = z.object({ input: z.string(), context: z.object({ user_id: z.string(), session_id: z.string(), timestamp: z.string(), location: z.string(), previous_actions: z.array(z.any()), environment_state: z.record(z.any()) }), model: z.enum(['claude', 'gpt4', 'custom']).optional() }); // Rate limiters const globalLimiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: rateLimitConfig.requests_per_minute }); const modelSpecificLimiter = (model: string) => rateLimit({ windowMs: 60 * 1000, max: rateLimitConfig.model_specific_limits[model as AIModel]?.requests_per_minute || rateLimitConfig.requests_per_minute }); // Error handler middleware const errorHandler = ( error: Error, req: express.Request, res: express.Response, next: express.NextFunction ) => { const aiError: AIError = { code: 'PROCESSING_ERROR', message: error.message, suggestion: 'Please try again with a different command format', recovery_options: [ 'Simplify your command', 'Use standard command patterns', 'Check device names and parameters' ], context: req.body.context }; res.status(500).json({ error: aiError }); }; // Endpoints router.post( '/interpret', globalLimiter, async (req: express.Request, res: express.Response, next: express.NextFunction) => { try { const { input, context, model = 'claude' } = interpretRequestSchema.parse(req.body); // Apply model-specific rate limiting modelSpecificLimiter(model)(req, res, async () => { const { intent, confidence, error } = await nlpProcessor.processCommand(input, context); if (error) { return res.status(400).json({ error }); } const isValid = await nlpProcessor.validateIntent(intent, confidence); if (!isValid) { const suggestions = await nlpProcessor.suggestCorrections(input, { code: 'INVALID_INTENT', message: 'Could not understand the command with high confidence', suggestion: 'Please try rephrasing your command', recovery_options: [], context }); return res.status(400).json({ error: { code: 'INVALID_INTENT', message: 'Could not understand the command with high confidence', suggestion: 'Please try rephrasing your command', recovery_options: suggestions, context } }); } const response: AIResponse = { natural_language: `I'll ${intent.action} the ${intent.target.split('.').pop()}`, structured_data: { success: true, action_taken: intent.action, entities_affected: [intent.target], state_changes: intent.parameters }, next_suggestions: [ 'Would you like to adjust any settings?', 'Should I perform this action in other rooms?', 'Would you like to schedule this action?' ], confidence, context }; res.json(response); }); } catch (error) { next(error); } } ); router.post( '/execute', globalLimiter, async (req: express.Request, res: express.Response, next: express.NextFunction) => { try { const { intent, context, model = 'claude' } = req.body; // Apply model-specific rate limiting modelSpecificLimiter(model)(req, res, async () => { // Execute the intent through Home Assistant // This would integrate with your existing Home Assistant service const response: AIResponse = { natural_language: `Successfully executed ${intent.action} on ${intent.target}`, structured_data: { success: true, action_taken: intent.action, entities_affected: [intent.target], state_changes: intent.parameters }, next_suggestions: [ 'Would you like to verify the state?', 'Should I perform any related actions?', 'Would you like to undo this action?' ], confidence: { overall: 1, intent: 1, entities: 1, context: 1 }, context }; res.json(response); }); } catch (error) { next(error); } } ); router.get( '/suggestions', globalLimiter, async (req: express.Request, res: express.Response, next: express.NextFunction) => { try { const { context, model = 'claude' } = req.body; // Apply model-specific rate limiting modelSpecificLimiter(model)(req, res, async () => { // Generate context-aware suggestions const suggestions = [ 'Turn on the lights in the living room', 'Set the temperature to 72 degrees', 'Show me the current state of all devices', 'Start the evening routine' ]; res.json({ suggestions }); }); } catch (error) { next(error); } } ); // Apply error handler router.use(errorHandler); export default router;