- Standardized error handling across tool implementations - Improved return type consistency for tool execution results - Simplified configuration parsing and type definitions - Enhanced type safety for various configuration schemas - Cleaned up and normalized tool response structures - Updated SSE and event subscription tool implementations
235 lines
5.9 KiB
TypeScript
235 lines
5.9 KiB
TypeScript
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;
|