UNPKG

orchestry-mcp

Version:

Orchestry MCP Server for multi-session task management

534 lines (483 loc) 16.8 kB
/** * Role-Based Task Management for Orchestry * * Manages task assignments based on LLM session roles and expertise */ import { DatabaseManager } from '../database-manager.js'; import { Priority, TaskStatus } from '../../shared/types.js'; // Define roles that LLM sessions can have export type LLMRole = | 'backend' | 'frontend' | 'fullstack' | 'devops' | 'database' | 'testing' | 'security' | 'ui-ux' | 'architect' | 'product-manager' | 'code-reviewer' | 'documentation'; // Role capabilities and preferred task types export const ROLE_CAPABILITIES: Record<LLMRole, { skills: string[]; preferredTasks: string[]; canReview: LLMRole[]; }> = { backend: { skills: ['API development', 'Database design', 'Server-side logic', 'Authentication'], preferredTasks: ['api', 'database', 'auth', 'server', 'integration'], canReview: ['frontend', 'database'], }, frontend: { skills: ['React', 'Vue', 'UI components', 'State management', 'Responsive design'], preferredTasks: ['ui', 'component', 'form', 'styling', 'ux'], canReview: ['ui-ux'], }, fullstack: { skills: ['End-to-end features', 'API integration', 'Full application flow'], preferredTasks: ['feature', 'integration', 'api', 'ui'], canReview: ['backend', 'frontend'], }, devops: { skills: ['CI/CD', 'Deployment', 'Infrastructure', 'Monitoring', 'Docker', 'Kubernetes'], preferredTasks: ['deployment', 'ci', 'infrastructure', 'monitoring', 'docker'], canReview: ['security'], }, database: { skills: ['Schema design', 'Query optimization', 'Migration', 'Data modeling'], preferredTasks: ['schema', 'migration', 'query', 'index', 'optimization'], canReview: ['backend'], }, testing: { skills: ['Unit tests', 'Integration tests', 'E2E tests', 'Test automation'], preferredTasks: ['test', 'testing', 'e2e', 'unit-test', 'integration-test'], canReview: ['fullstack', 'backend', 'frontend'], }, security: { skills: ['Security audit', 'Vulnerability assessment', 'Authentication', 'Authorization'], preferredTasks: ['security', 'auth', 'vulnerability', 'audit', 'encryption'], canReview: ['backend', 'devops'], }, 'ui-ux': { skills: ['Design systems', 'User experience', 'Wireframes', 'Prototypes'], preferredTasks: ['design', 'ux', 'wireframe', 'prototype', 'user-flow'], canReview: ['frontend'], }, architect: { skills: ['System design', 'Architecture patterns', 'Technology selection'], preferredTasks: ['architecture', 'design', 'pattern', 'structure', 'planning'], canReview: ['fullstack', 'backend', 'database'], }, 'product-manager': { skills: ['Requirements', 'User stories', 'Prioritization', 'Roadmap'], preferredTasks: ['requirements', 'story', 'epic', 'planning', 'specification'], canReview: ['ui-ux'], }, 'code-reviewer': { skills: ['Code quality', 'Best practices', 'Performance review', 'Security review'], preferredTasks: ['review', 'refactor', 'optimization', 'quality'], canReview: ['backend', 'frontend', 'fullstack'], }, documentation: { skills: ['API docs', 'User guides', 'Technical writing', 'README'], preferredTasks: ['docs', 'documentation', 'readme', 'guide', 'tutorial'], canReview: [], }, }; // Priority matrix for automatic prioritization export const PRIORITY_MATRIX = { // Task type to base priority mapping taskTypes: { security: 'critical', bug: 'high', feature: 'medium', enhancement: 'medium', documentation: 'low', refactor: 'low', }, // Keywords that affect priority keywords: { urgent: 'critical', asap: 'critical', blocker: 'critical', critical: 'critical', important: 'high', breaking: 'high', crash: 'high', security: 'critical', vulnerability: 'critical', optimization: 'low', 'nice-to-have': 'low', }, // Dependencies increase priority hasDependents: { many: 'high', // 3+ tasks depend on this some: 'medium', // 1-2 tasks depend on this none: null, // No change }, }; export class RoleBasedTaskManager { private sessions: Map<string, { role: LLMRole; currentLoad: number; expertise: string[]; availability: 'available' | 'busy' | 'away'; }> = new Map(); constructor(private dbManager: DatabaseManager) {} /** * Register a new LLM session with a role */ registerSession(sessionId: string, role: LLMRole, expertise?: string[]) { this.sessions.set(sessionId, { role, currentLoad: 0, expertise: expertise || ROLE_CAPABILITIES[role].skills, availability: 'available', }); return { sessionId, role, capabilities: ROLE_CAPABILITIES[role], }; } /** * Automatically assign a task to the best available session */ async autoAssignTask( taskTitle: string, taskDescription: string, requiredSkills?: string[] ): Promise<{ assignedTo: string; role: LLMRole; priority: Priority; reason: string; }> { // Determine priority automatically const priority = this.determinePriority(taskTitle, taskDescription); // Find best match based on task requirements let bestMatch: { sessionId: string; score: number } | null = null; for (const [sessionId, session] of this.sessions) { if (session.availability !== 'available') continue; // Calculate match score let score = 0; // Check if role matches task type const taskKeywords = (taskTitle + ' ' + taskDescription).toLowerCase(); for (const preferred of ROLE_CAPABILITIES[session.role].preferredTasks) { if (taskKeywords.includes(preferred)) { score += 10; } } // Check skill match if (requiredSkills) { for (const skill of requiredSkills) { if (session.expertise.includes(skill)) { score += 5; } } } // Factor in current load (prefer less loaded sessions) score -= session.currentLoad * 2; if (!bestMatch || score > bestMatch.score) { bestMatch = { sessionId, score }; } } if (!bestMatch) { // No available session, create a task pool entry return { assignedTo: 'pool', role: 'fullstack' as LLMRole, priority, reason: 'No available session. Task added to pool for next available agent.', }; } const session = this.sessions.get(bestMatch.sessionId)!; session.currentLoad++; return { assignedTo: bestMatch.sessionId, role: session.role, priority, reason: `Best match based on ${session.role} expertise and availability`, }; } /** * Determine priority based on content analysis */ private determinePriority(title: string, description: string): Priority { const content = (title + ' ' + description).toLowerCase(); // Check for priority keywords for (const [keyword, priority] of Object.entries(PRIORITY_MATRIX.keywords)) { if (content.includes(keyword)) { return priority as Priority; } } // Check task type for (const [type, priority] of Object.entries(PRIORITY_MATRIX.taskTypes)) { if (content.includes(type)) { return priority as Priority; } } // Default to medium return 'medium'; } /** * Get recommended next task for a session based on role */ async getNextTask(sessionId: string): Promise<{ task: any; reason: string; } | null> { const session = this.sessions.get(sessionId); if (!session) return null; // This would query the database for unassigned tasks // matching the session's role and expertise // Prioritizing by priority and dependencies return { task: { title: 'Implement user authentication', priority: 'high', estimatedHours: 4, }, reason: `High priority task matching ${session.role} expertise`, }; } /** * Load balancing - redistribute tasks if a session becomes unavailable */ async redistributeTasks(unavailableSessionId: string) { const session = this.sessions.get(unavailableSessionId); if (!session) return; session.availability = 'away'; // Find tasks assigned to this session and reassign them // This would query the database and reassign based on priority console.log(`Redistributing tasks from ${unavailableSessionId}`); } /** * Get workload distribution across all sessions */ getWorkloadDistribution() { const distribution: Record<LLMRole, { sessions: number; totalLoad: number; averageLoad: number; }> = {} as any; for (const [_, session] of this.sessions) { if (!distribution[session.role]) { distribution[session.role] = { sessions: 0, totalLoad: 0, averageLoad: 0, }; } distribution[session.role].sessions++; distribution[session.role].totalLoad += session.currentLoad; } // Calculate averages for (const role in distribution) { const data = distribution[role as LLMRole]; data.averageLoad = data.totalLoad / data.sessions; } return distribution; } } /** * Enhanced collaboration tools with role-based features */ export class EnhancedCollaborationTools { private taskManager: RoleBasedTaskManager; constructor(private dbManager: DatabaseManager) { this.taskManager = new RoleBasedTaskManager(dbManager); } getEnhancedTools() { return [ { name: 'register_session_role', description: `Register this LLM session with a specific role and expertise. This helps with automatic task assignment and workload distribution. Example: register_session_role("backend", ["Node.js", "PostgreSQL", "REST APIs"])`, inputSchema: { type: 'object', properties: { role: { type: 'string', enum: ['backend', 'frontend', 'fullstack', 'devops', 'database', 'testing', 'security', 'ui-ux', 'architect', 'product-manager', 'code-reviewer', 'documentation'], description: 'Your primary role in this session', }, expertise: { type: 'array', items: { type: 'string' }, description: 'Specific technologies or areas you can handle', }, sessionName: { type: 'string', description: 'Optional friendly name for this session' }, }, required: ['role'], }, }, { name: 'create_prioritized_task', description: `Create a task with automatic priority and assignment. The system will determine priority based on content and assign to the best available session. Example: create_prioritized_task("Fix security vulnerability in login", "SQL injection risk found")`, inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Task title' }, description: { type: 'string', description: 'Detailed task description' }, requiredSkills: { type: 'array', items: { type: 'string' }, description: 'Skills needed for this task', }, explicitPriority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'Override automatic priority detection', }, preferredRole: { type: 'string', enum: ['backend', 'frontend', 'fullstack', 'devops', 'database', 'testing', 'security', 'ui-ux', 'architect'], description: 'Preferred role for this task', }, dependencies: { type: 'array', items: { type: 'string' }, description: 'Task IDs this depends on', }, estimatedHours: { type: 'number', description: 'Estimated hours to complete' }, }, required: ['title', 'description'], }, }, { name: 'claim_next_task', description: `Get the next appropriate task for your role and expertise. System will recommend the highest priority task matching your capabilities. Example: claim_next_task()`, inputSchema: { type: 'object', properties: { taskType: { type: 'string', description: 'Optional: specific type of task you want', }, }, }, }, { name: 'update_task_assignment', description: `Update task assignment and priority. Example: update_task_assignment("task-123", "session-backend-1", "critical")`, inputSchema: { type: 'object', properties: { taskId: { type: 'string', description: 'Task ID' }, assignTo: { type: 'string', description: 'Session ID or "pool" for unassigned' }, priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'New priority', }, reason: { type: 'string', description: 'Reason for reassignment' }, }, required: ['taskId'], }, }, { name: 'get_role_workload', description: `Check workload distribution across all roles. Helps identify bottlenecks and overloaded roles. Example: get_role_workload()`, inputSchema: { type: 'object', properties: {}, }, }, { name: 'request_role_specific_help', description: `Request help from a specific role. Example: request_role_specific_help("database", "Need help optimizing this query", "SELECT * FROM users...")`, inputSchema: { type: 'object', properties: { targetRole: { type: 'string', enum: ['backend', 'frontend', 'fullstack', 'devops', 'database', 'testing', 'security', 'ui-ux', 'architect'], description: 'Role you need help from', }, issue: { type: 'string', description: 'What you need help with' }, context: { type: 'string', description: 'Current code or situation' }, priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'How urgent is this', }, }, required: ['targetRole', 'issue'], }, }, { name: 'escalate_task', description: `Escalate a task to higher priority or different role. Use when you discover a task is more complex or critical than initially thought. Example: escalate_task("task-123", "critical", "architect", "Requires system redesign")`, inputSchema: { type: 'object', properties: { taskId: { type: 'string', description: 'Task to escalate' }, newPriority: { type: 'string', enum: ['high', 'critical'], description: 'New priority level', }, escalateToRole: { type: 'string', enum: ['architect', 'security', 'product-manager'], description: 'Role to escalate to', }, reason: { type: 'string', description: 'Why escalation is needed' }, }, required: ['taskId', 'reason'], }, }, ]; } } /** * Priority queue for task management */ export class TaskPriorityQueue { private queues: Map<Priority, any[]> = new Map([ ['critical', []], ['high', []], ['medium', []], ['low', []], ]); addTask(task: any, priority: Priority) { this.queues.get(priority)?.push(task); } getNextTask(): any | null { // Get highest priority task for (const priority of ['critical', 'high', 'medium', 'low'] as Priority[]) { const queue = this.queues.get(priority); if (queue && queue.length > 0) { return queue.shift(); } } return null; } getQueueStatus() { const status: Record<Priority, number> = { critical: this.queues.get('critical')?.length || 0, high: this.queues.get('high')?.length || 0, medium: this.queues.get('medium')?.length || 0, low: this.queues.get('low')?.length || 0, }; return status; } }