/ components / agents / validateAgent.ts
validateAgent.ts
  1  import type { Tools } from '../../Tool.js'
  2  import { resolveAgentTools } from '../../tools/AgentTool/agentToolUtils.js'
  3  import type {
  4    AgentDefinition,
  5    CustomAgentDefinition,
  6  } from '../../tools/AgentTool/loadAgentsDir.js'
  7  import { getAgentSourceDisplayName } from './utils.js'
  8  
  9  export type AgentValidationResult = {
 10    isValid: boolean
 11    errors: string[]
 12    warnings: string[]
 13  }
 14  
 15  export function validateAgentType(agentType: string): string | null {
 16    if (!agentType) {
 17      return 'Agent type is required'
 18    }
 19  
 20    if (!/^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$/.test(agentType)) {
 21      return 'Agent type must start and end with alphanumeric characters and contain only letters, numbers, and hyphens'
 22    }
 23  
 24    if (agentType.length < 3) {
 25      return 'Agent type must be at least 3 characters long'
 26    }
 27  
 28    if (agentType.length > 50) {
 29      return 'Agent type must be less than 50 characters'
 30    }
 31  
 32    return null
 33  }
 34  
 35  export function validateAgent(
 36    agent: Omit<CustomAgentDefinition, 'location'>,
 37    availableTools: Tools,
 38    existingAgents: AgentDefinition[],
 39  ): AgentValidationResult {
 40    const errors: string[] = []
 41    const warnings: string[] = []
 42  
 43    // Validate agent type
 44    if (!agent.agentType) {
 45      errors.push('Agent type is required')
 46    } else {
 47      const typeError = validateAgentType(agent.agentType)
 48      if (typeError) {
 49        errors.push(typeError)
 50      }
 51  
 52      // Check for duplicates (excluding self for editing)
 53      const duplicate = existingAgents.find(
 54        a => a.agentType === agent.agentType && a.source !== agent.source,
 55      )
 56      if (duplicate) {
 57        errors.push(
 58          `Agent type "${agent.agentType}" already exists in ${getAgentSourceDisplayName(duplicate.source)}`,
 59        )
 60      }
 61    }
 62  
 63    // Validate description
 64    if (!agent.whenToUse) {
 65      errors.push('Description (description) is required')
 66    } else if (agent.whenToUse.length < 10) {
 67      warnings.push(
 68        'Description should be more descriptive (at least 10 characters)',
 69      )
 70    } else if (agent.whenToUse.length > 5000) {
 71      warnings.push('Description is very long (over 5000 characters)')
 72    }
 73  
 74    // Validate tools
 75    if (agent.tools !== undefined && !Array.isArray(agent.tools)) {
 76      errors.push('Tools must be an array')
 77    } else {
 78      if (agent.tools === undefined) {
 79        warnings.push('Agent has access to all tools')
 80      } else if (agent.tools.length === 0) {
 81        warnings.push(
 82          'No tools selected - agent will have very limited capabilities',
 83        )
 84      }
 85  
 86      // Check for invalid tools
 87      const resolvedTools = resolveAgentTools(agent, availableTools, false)
 88  
 89      if (resolvedTools.invalidTools.length > 0) {
 90        errors.push(`Invalid tools: ${resolvedTools.invalidTools.join(', ')}`)
 91      }
 92    }
 93  
 94    // Validate system prompt
 95    const systemPrompt = agent.getSystemPrompt()
 96    if (!systemPrompt) {
 97      errors.push('System prompt is required')
 98    } else if (systemPrompt.length < 20) {
 99      errors.push('System prompt is too short (minimum 20 characters)')
100    } else if (systemPrompt.length > 10000) {
101      warnings.push('System prompt is very long (over 10,000 characters)')
102    }
103  
104    return {
105      isValid: errors.length === 0,
106      errors,
107      warnings,
108    }
109  }