Add REST API endpoints for the PlantLineageAgent: - GET /api/agents/lineage - Agent status and network statistics - POST /api/agents/lineage - Start/stop/pause/resume agent - GET /api/agents/lineage/[plantId] - Lineage analysis for specific plant - GET /api/agents/lineage/anomalies - List detected lineage anomalies Includes comprehensive test suite with 25 passing tests.
79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
/**
|
|
* API Route: Get lineage anomalies detected by PlantLineageAgent
|
|
* GET /api/agents/lineage/anomalies
|
|
*/
|
|
|
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
import { getPlantLineageAgent } from '../../../../lib/agents';
|
|
|
|
export default async function handler(
|
|
req: NextApiRequest,
|
|
res: NextApiResponse
|
|
) {
|
|
if (req.method !== 'GET') {
|
|
return res.status(405).json({ success: false, error: 'Method not allowed' });
|
|
}
|
|
|
|
try {
|
|
const { severity, type, limit } = req.query;
|
|
const agent = getPlantLineageAgent();
|
|
|
|
let anomalies = agent.getAnomalies();
|
|
|
|
// Filter by severity if specified
|
|
if (severity && typeof severity === 'string') {
|
|
const validSeverities = ['low', 'medium', 'high'];
|
|
if (!validSeverities.includes(severity)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: `Invalid severity. Must be one of: ${validSeverities.join(', ')}`
|
|
});
|
|
}
|
|
anomalies = anomalies.filter(a => a.severity === severity);
|
|
}
|
|
|
|
// Filter by type if specified
|
|
if (type && typeof type === 'string') {
|
|
const validTypes = ['orphan', 'circular', 'invalid_generation', 'missing_parent', 'suspicious_location'];
|
|
if (!validTypes.includes(type)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: `Invalid type. Must be one of: ${validTypes.join(', ')}`
|
|
});
|
|
}
|
|
anomalies = anomalies.filter(a => a.type === type);
|
|
}
|
|
|
|
// Apply limit if specified
|
|
const maxResults = limit ? Math.min(parseInt(limit as string, 10), 100) : 50;
|
|
anomalies = anomalies.slice(0, maxResults);
|
|
|
|
// Group by type for summary
|
|
const byType: Record<string, number> = {};
|
|
const bySeverity: Record<string, number> = {};
|
|
const allAnomalies = agent.getAnomalies();
|
|
|
|
for (const anomaly of allAnomalies) {
|
|
byType[anomaly.type] = (byType[anomaly.type] || 0) + 1;
|
|
bySeverity[anomaly.severity] = (bySeverity[anomaly.severity] || 0) + 1;
|
|
}
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
summary: {
|
|
total: allAnomalies.length,
|
|
byType,
|
|
bySeverity,
|
|
},
|
|
filters: {
|
|
severity: severity || null,
|
|
type: type || null,
|
|
limit: maxResults,
|
|
},
|
|
anomalies,
|
|
});
|
|
} catch (error: any) {
|
|
console.error('Error getting lineage anomalies:', error);
|
|
res.status(500).json({ success: false, error: error.message || 'Internal server error' });
|
|
}
|
|
}
|