feat(agents): add frontend types and validation for category fields

Frontend changes to support new AgentType category and display fields:

Types (agentTypes.ts):
- Add AgentTypeCategory union type with 8 categories
- Add CATEGORY_METADATA constant with labels, descriptions, colors
- Update all interfaces with new fields (category, icon, color, etc.)
- Add AgentTypeGroupedResponse type

Validation (agentType.ts):
- Add AGENT_TYPE_CATEGORIES constant with metadata
- Add AVAILABLE_ICONS constant for icon picker
- Add COLOR_PALETTE constant for color selection
- Update agentTypeFormSchema with new field validators
- Update defaultAgentTypeValues with new fields

Form updates:
- Transform function now maps category and display fields from API

Test updates:
- Add new fields to mock AgentTypeResponse objects

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-06 16:16:21 +01:00
parent 9339ea30a1
commit 5717bffd63
6 changed files with 253 additions and 0 deletions

View File

@@ -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 {

View File

@@ -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<string, unknown>;
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<string, unknown>;
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<string, unknown> | 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<string, unknown>;
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<string, AgentTypeResponse[]>;
/**
* Model parameter configuration with typed fields
*/

View File

@@ -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: [],
};
/**

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,