diff --git a/frontend/src/components/agents/AgentTypeForm.tsx b/frontend/src/components/agents/AgentTypeForm.tsx index cd4fd00..2a67c5f 100644 --- a/frontend/src/components/agents/AgentTypeForm.tsx +++ b/frontend/src/components/agents/AgentTypeForm.tsx @@ -96,6 +96,13 @@ function transformAgentTypeToFormValues( mcp_servers: agentType.mcp_servers, tool_permissions: agentType.tool_permissions, is_active: agentType.is_active, + // Category and display fields + category: agentType.category, + icon: agentType.icon, + color: agentType.color, + sort_order: agentType.sort_order ?? 0, + typical_tasks: agentType.typical_tasks ?? [], + collaboration_hints: agentType.collaboration_hints ?? [], }); return { diff --git a/frontend/src/lib/api/types/agentTypes.ts b/frontend/src/lib/api/types/agentTypes.ts index 6110cf0..43e605e 100644 --- a/frontend/src/lib/api/types/agentTypes.ts +++ b/frontend/src/lib/api/types/agentTypes.ts @@ -5,6 +5,68 @@ * Used for type-safe API communication with the agent-types endpoints. */ +/** + * Category classification for agent types + */ +export type AgentTypeCategory = + | 'development' + | 'design' + | 'quality' + | 'operations' + | 'ai_ml' + | 'data' + | 'leadership' + | 'domain_expert'; + +/** + * Metadata for each category including display label and description + */ +export const CATEGORY_METADATA: Record< + AgentTypeCategory, + { label: string; description: string; color: string } +> = { + development: { + label: 'Development', + description: 'Product, project, and engineering roles', + color: '#3B82F6', + }, + design: { + label: 'Design', + description: 'UI/UX and design research', + color: '#EC4899', + }, + quality: { + label: 'Quality', + description: 'QA and security assurance', + color: '#10B981', + }, + operations: { + label: 'Operations', + description: 'DevOps and MLOps engineering', + color: '#F59E0B', + }, + ai_ml: { + label: 'AI & ML', + description: 'Machine learning specialists', + color: '#8B5CF6', + }, + data: { + label: 'Data', + description: 'Data science and engineering', + color: '#06B6D4', + }, + leadership: { + label: 'Leadership', + description: 'Technical leadership and facilitation', + color: '#F97316', + }, + domain_expert: { + label: 'Domain Experts', + description: 'Industry and domain specialists', + color: '#84CC16', + }, +}; + /** * Base agent type fields shared across create, update, and response schemas */ @@ -20,6 +82,13 @@ export interface AgentTypeBase { mcp_servers: string[]; tool_permissions: Record; is_active: boolean; + // Category and display fields + category?: AgentTypeCategory | null; + icon?: string | null; + color?: string | null; + sort_order: number; + typical_tasks: string[]; + collaboration_hints: string[]; } /** @@ -37,6 +106,13 @@ export interface AgentTypeCreate { mcp_servers?: string[]; tool_permissions?: Record; is_active?: boolean; + // Category and display fields + category?: AgentTypeCategory | null; + icon?: string | null; + color?: string | null; + sort_order?: number; + typical_tasks?: string[]; + collaboration_hints?: string[]; } /** @@ -54,6 +130,13 @@ export interface AgentTypeUpdate { mcp_servers?: string[] | null; tool_permissions?: Record | null; is_active?: boolean | null; + // Category and display fields + category?: AgentTypeCategory | null; + icon?: string | null; + color?: string | null; + sort_order?: number | null; + typical_tasks?: string[] | null; + collaboration_hints?: string[] | null; } /** @@ -72,6 +155,13 @@ export interface AgentTypeResponse { mcp_servers: string[]; tool_permissions: Record; is_active: boolean; + // Category and display fields + category: AgentTypeCategory | null; + icon: string | null; + color: string | null; + sort_order: number; + typical_tasks: string[]; + collaboration_hints: string[]; created_at: string; updated_at: string; instance_count: number; @@ -104,9 +194,15 @@ export interface AgentTypeListParams { page?: number; limit?: number; is_active?: boolean; + category?: AgentTypeCategory; search?: string; } +/** + * Response type for grouped agent types by category + */ +export type AgentTypeGroupedResponse = Record; + /** * Model parameter configuration with typed fields */ diff --git a/frontend/src/lib/validations/agentType.ts b/frontend/src/lib/validations/agentType.ts index 5979b5c..670e0db 100644 --- a/frontend/src/lib/validations/agentType.ts +++ b/frontend/src/lib/validations/agentType.ts @@ -6,12 +6,18 @@ */ import { z } from 'zod'; +import type { AgentTypeCategory } from '@/lib/api/types/agentTypes'; /** * Slug validation regex: lowercase letters, numbers, and hyphens only */ const slugRegex = /^[a-z0-9-]+$/; +/** + * Hex color validation regex + */ +const hexColorRegex = /^#[0-9A-Fa-f]{6}$/; + /** * Available AI models for agent types */ @@ -43,6 +49,84 @@ export const AGENT_TYPE_STATUS = [ { value: false, label: 'Inactive' }, ] as const; +/** + * Agent type categories for organizing agents + */ +/* istanbul ignore next -- constant declaration */ +export const AGENT_TYPE_CATEGORIES: { + value: AgentTypeCategory; + label: string; + description: string; +}[] = [ + { value: 'development', label: 'Development', description: 'Product, project, and engineering' }, + { value: 'design', label: 'Design', description: 'UI/UX and design research' }, + { value: 'quality', label: 'Quality', description: 'QA and security assurance' }, + { value: 'operations', label: 'Operations', description: 'DevOps and MLOps engineering' }, + { value: 'ai_ml', label: 'AI & ML', description: 'Machine learning specialists' }, + { value: 'data', label: 'Data', description: 'Data science and engineering' }, + { value: 'leadership', label: 'Leadership', description: 'Technical leadership' }, + { value: 'domain_expert', label: 'Domain Experts', description: 'Industry specialists' }, +]; + +/** + * Available Lucide icons for agent types + */ +/* istanbul ignore next -- constant declaration */ +export const AVAILABLE_ICONS = [ + // Development + { value: 'clipboard-check', label: 'Clipboard Check', category: 'development' }, + { value: 'briefcase', label: 'Briefcase', category: 'development' }, + { value: 'file-text', label: 'File Text', category: 'development' }, + { value: 'git-branch', label: 'Git Branch', category: 'development' }, + { value: 'code', label: 'Code', category: 'development' }, + { value: 'server', label: 'Server', category: 'development' }, + { value: 'layout', label: 'Layout', category: 'development' }, + { value: 'smartphone', label: 'Smartphone', category: 'development' }, + // Design + { value: 'palette', label: 'Palette', category: 'design' }, + { value: 'search', label: 'Search', category: 'design' }, + // Quality + { value: 'shield', label: 'Shield', category: 'quality' }, + { value: 'shield-check', label: 'Shield Check', category: 'quality' }, + // Operations + { value: 'settings', label: 'Settings', category: 'operations' }, + { value: 'settings-2', label: 'Settings 2', category: 'operations' }, + // AI/ML + { value: 'brain', label: 'Brain', category: 'ai_ml' }, + { value: 'microscope', label: 'Microscope', category: 'ai_ml' }, + { value: 'eye', label: 'Eye', category: 'ai_ml' }, + { value: 'message-square', label: 'Message Square', category: 'ai_ml' }, + // Data + { value: 'bar-chart', label: 'Bar Chart', category: 'data' }, + { value: 'database', label: 'Database', category: 'data' }, + // Leadership + { value: 'users', label: 'Users', category: 'leadership' }, + { value: 'target', label: 'Target', category: 'leadership' }, + // Domain Expert + { value: 'calculator', label: 'Calculator', category: 'domain_expert' }, + { value: 'heart-pulse', label: 'Heart Pulse', category: 'domain_expert' }, + { value: 'flask-conical', label: 'Flask', category: 'domain_expert' }, + { value: 'lightbulb', label: 'Lightbulb', category: 'domain_expert' }, + { value: 'book-open', label: 'Book Open', category: 'domain_expert' }, + // Generic + { value: 'bot', label: 'Bot', category: 'generic' }, +] as const; + +/** + * Color palette for agent type visual distinction + */ +/* istanbul ignore next -- constant declaration */ +export const COLOR_PALETTE = [ + { value: '#3B82F6', label: 'Blue', category: 'development' }, + { value: '#EC4899', label: 'Pink', category: 'design' }, + { value: '#10B981', label: 'Green', category: 'quality' }, + { value: '#F59E0B', label: 'Amber', category: 'operations' }, + { value: '#8B5CF6', label: 'Purple', category: 'ai_ml' }, + { value: '#06B6D4', label: 'Cyan', category: 'data' }, + { value: '#F97316', label: 'Orange', category: 'leadership' }, + { value: '#84CC16', label: 'Lime', category: 'domain_expert' }, +] as const; + /** * Model params schema */ @@ -52,6 +136,20 @@ const modelParamsSchema = z.object({ top_p: z.number().min(0).max(1), }); +/** + * Agent type category enum values + */ +const agentTypeCategoryValues = [ + 'development', + 'design', + 'quality', + 'operations', + 'ai_ml', + 'data', + 'leadership', + 'domain_expert', +] as const; + /** * Schema for agent type form fields */ @@ -96,6 +194,23 @@ export const agentTypeFormSchema = z.object({ tool_permissions: z.record(z.string(), z.unknown()), is_active: z.boolean(), + + // Category and display fields + category: z.enum(agentTypeCategoryValues).nullable().optional(), + + icon: z.string().max(50, 'Icon must be less than 50 characters').nullable().optional(), + + color: z + .string() + .regex(hexColorRegex, 'Color must be a valid hex code (e.g., #3B82F6)') + .nullable() + .optional(), + + sort_order: z.number().int().min(0).max(1000), + + typical_tasks: z.array(z.string()), + + collaboration_hints: z.array(z.string()), }); /** @@ -138,6 +253,13 @@ export const defaultAgentTypeValues: AgentTypeCreateFormValues = { mcp_servers: [], tool_permissions: {}, is_active: false, // Start as draft + // Category and display fields + category: null, + icon: 'bot', + color: '#3B82F6', + sort_order: 0, + typical_tasks: [], + collaboration_hints: [], }; /** diff --git a/frontend/tests/components/agents/AgentTypeDetail.test.tsx b/frontend/tests/components/agents/AgentTypeDetail.test.tsx index 8255e65..a394dc2 100644 --- a/frontend/tests/components/agents/AgentTypeDetail.test.tsx +++ b/frontend/tests/components/agents/AgentTypeDetail.test.tsx @@ -21,6 +21,13 @@ Your approach is: mcp_servers: ['gitea', 'knowledge', 'filesystem'], tool_permissions: {}, is_active: true, + // Category and display fields + category: 'development', + icon: 'git-branch', + color: '#3B82F6', + sort_order: 40, + typical_tasks: ['Design system architecture', 'Create ADRs'], + collaboration_hints: ['backend-engineer', 'frontend-engineer'], created_at: '2025-01-10T00:00:00Z', updated_at: '2025-01-18T00:00:00Z', instance_count: 2, diff --git a/frontend/tests/components/agents/AgentTypeForm.test.tsx b/frontend/tests/components/agents/AgentTypeForm.test.tsx index 276d5ec..4656b5a 100644 --- a/frontend/tests/components/agents/AgentTypeForm.test.tsx +++ b/frontend/tests/components/agents/AgentTypeForm.test.tsx @@ -16,6 +16,13 @@ const mockAgentType: AgentTypeResponse = { mcp_servers: ['gitea'], tool_permissions: {}, is_active: true, + // Category and display fields + category: 'development', + icon: 'git-branch', + color: '#3B82F6', + sort_order: 40, + typical_tasks: ['Design system architecture'], + collaboration_hints: ['backend-engineer'], created_at: '2025-01-10T00:00:00Z', updated_at: '2025-01-18T00:00:00Z', instance_count: 2, diff --git a/frontend/tests/components/agents/AgentTypeList.test.tsx b/frontend/tests/components/agents/AgentTypeList.test.tsx index d00be42..f761780 100644 --- a/frontend/tests/components/agents/AgentTypeList.test.tsx +++ b/frontend/tests/components/agents/AgentTypeList.test.tsx @@ -17,6 +17,13 @@ const mockAgentTypes: AgentTypeResponse[] = [ mcp_servers: ['gitea', 'knowledge'], tool_permissions: {}, is_active: true, + // Category and display fields + category: 'development', + icon: 'clipboard-check', + color: '#3B82F6', + sort_order: 10, + typical_tasks: ['Manage backlog', 'Write user stories'], + collaboration_hints: ['business-analyst', 'scrum-master'], created_at: '2025-01-15T00:00:00Z', updated_at: '2025-01-20T00:00:00Z', instance_count: 3, @@ -34,6 +41,13 @@ const mockAgentTypes: AgentTypeResponse[] = [ mcp_servers: ['gitea'], tool_permissions: {}, is_active: false, + // Category and display fields + category: 'development', + icon: 'git-branch', + color: '#3B82F6', + sort_order: 40, + typical_tasks: ['Design architecture', 'Create ADRs'], + collaboration_hints: ['backend-engineer', 'devops-engineer'], created_at: '2025-01-10T00:00:00Z', updated_at: '2025-01-18T00:00:00Z', instance_count: 0,