- Agent roles and coordination features - Chat API integration testing - New configuration and workspace management 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
495 lines
14 KiB
Go
495 lines
14 KiB
Go
package agent
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// AgentRole represents different agent roles in the system
|
|
type AgentRole string
|
|
|
|
const (
|
|
BackendRole AgentRole = "backend"
|
|
FrontendRole AgentRole = "frontend"
|
|
DevOpsRole AgentRole = "devops"
|
|
QARole AgentRole = "qa"
|
|
TestingRole AgentRole = "testing"
|
|
GeneralRole AgentRole = "general"
|
|
)
|
|
|
|
// RoleCapability represents capabilities of an agent role
|
|
type RoleCapability struct {
|
|
Name string
|
|
Description string
|
|
Weight float64
|
|
}
|
|
|
|
// DirectoryScope represents directory patterns for context filtering
|
|
type DirectoryScope struct {
|
|
Patterns []string
|
|
Description string
|
|
}
|
|
|
|
// RoleConfig holds configuration for an agent role
|
|
type RoleConfig struct {
|
|
Role AgentRole
|
|
DisplayName string
|
|
Description string
|
|
Capabilities []RoleCapability
|
|
DirectoryScopes DirectoryScope
|
|
TaskTypes []string
|
|
Priority int
|
|
|
|
// Context filtering parameters
|
|
ContextWeight float64
|
|
FeedbackWeight float64
|
|
LearningRate float64
|
|
}
|
|
|
|
// RoleManager manages agent roles and their configurations
|
|
type RoleManager struct {
|
|
roles map[AgentRole]*RoleConfig
|
|
agentRoles map[string]AgentRole // Maps agent ID to role
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
// NewRoleManager creates a new role manager with default configurations
|
|
func NewRoleManager() *RoleManager {
|
|
rm := &RoleManager{
|
|
roles: make(map[AgentRole]*RoleConfig),
|
|
agentRoles: make(map[string]AgentRole),
|
|
}
|
|
|
|
rm.initializeDefaultRoles()
|
|
return rm
|
|
}
|
|
|
|
// initializeDefaultRoles sets up default role configurations
|
|
func (rm *RoleManager) initializeDefaultRoles() {
|
|
// Backend role configuration
|
|
rm.roles[BackendRole] = &RoleConfig{
|
|
Role: BackendRole,
|
|
DisplayName: "Backend Developer",
|
|
Description: "Specializes in server-side development, APIs, databases, and backend services",
|
|
Capabilities: []RoleCapability{
|
|
{Name: "api_development", Description: "REST/GraphQL API development", Weight: 1.0},
|
|
{Name: "database_design", Description: "Database schema and query optimization", Weight: 0.9},
|
|
{Name: "server_architecture", Description: "Server architecture and microservices", Weight: 0.9},
|
|
{Name: "authentication", Description: "Authentication and authorization systems", Weight: 0.8},
|
|
{Name: "caching", Description: "Caching strategies and implementation", Weight: 0.8},
|
|
},
|
|
DirectoryScopes: DirectoryScope{
|
|
Patterns: []string{
|
|
"*/backend/*",
|
|
"*/api/*",
|
|
"*/services/*",
|
|
"*/server/*",
|
|
"*/core/*",
|
|
"*/models/*",
|
|
"*/controllers/*",
|
|
"*/middleware/*",
|
|
},
|
|
Description: "Backend-related directories and server-side code",
|
|
},
|
|
TaskTypes: []string{
|
|
"api_development",
|
|
"database_migration",
|
|
"backend_optimization",
|
|
"server_configuration",
|
|
"authentication_setup",
|
|
},
|
|
Priority: 5,
|
|
ContextWeight: 1.0,
|
|
FeedbackWeight: 0.3,
|
|
LearningRate: 0.1,
|
|
}
|
|
|
|
// Frontend role configuration
|
|
rm.roles[FrontendRole] = &RoleConfig{
|
|
Role: FrontendRole,
|
|
DisplayName: "Frontend Developer",
|
|
Description: "Specializes in user interfaces, client-side logic, and user experience",
|
|
Capabilities: []RoleCapability{
|
|
{Name: "ui_development", Description: "User interface development", Weight: 1.0},
|
|
{Name: "responsive_design", Description: "Responsive and mobile-first design", Weight: 0.9},
|
|
{Name: "state_management", Description: "Client-side state management", Weight: 0.8},
|
|
{Name: "component_architecture", Description: "Component-based architecture", Weight: 0.9},
|
|
{Name: "accessibility", Description: "Web accessibility implementation", Weight: 0.7},
|
|
},
|
|
DirectoryScopes: DirectoryScope{
|
|
Patterns: []string{
|
|
"*/frontend/*",
|
|
"*/ui/*",
|
|
"*/client/*",
|
|
"*/web/*",
|
|
"*/components/*",
|
|
"*/pages/*",
|
|
"*/styles/*",
|
|
"*/assets/*",
|
|
},
|
|
Description: "Frontend-related directories and client-side code",
|
|
},
|
|
TaskTypes: []string{
|
|
"ui_implementation",
|
|
"component_development",
|
|
"responsive_design",
|
|
"frontend_optimization",
|
|
"user_experience",
|
|
},
|
|
Priority: 4,
|
|
ContextWeight: 0.8,
|
|
FeedbackWeight: 0.3,
|
|
LearningRate: 0.1,
|
|
}
|
|
|
|
// DevOps role configuration
|
|
rm.roles[DevOpsRole] = &RoleConfig{
|
|
Role: DevOpsRole,
|
|
DisplayName: "DevOps Engineer",
|
|
Description: "Specializes in deployment, infrastructure, CI/CD, and system operations",
|
|
Capabilities: []RoleCapability{
|
|
{Name: "infrastructure", Description: "Infrastructure as Code", Weight: 1.0},
|
|
{Name: "containerization", Description: "Docker and container orchestration", Weight: 0.9},
|
|
{Name: "ci_cd", Description: "Continuous Integration/Deployment", Weight: 0.9},
|
|
{Name: "monitoring", Description: "System monitoring and alerting", Weight: 0.8},
|
|
{Name: "security", Description: "Security and compliance", Weight: 0.8},
|
|
},
|
|
DirectoryScopes: DirectoryScope{
|
|
Patterns: []string{
|
|
"*/deploy/*",
|
|
"*/config/*",
|
|
"*/docker/*",
|
|
"*/k8s/*",
|
|
"*/kubernetes/*",
|
|
"*/infrastructure/*",
|
|
"*/scripts/*",
|
|
"*/ci/*",
|
|
"*.yml",
|
|
"*.yaml",
|
|
"Dockerfile*",
|
|
"docker-compose*",
|
|
},
|
|
Description: "DevOps-related configuration and deployment files",
|
|
},
|
|
TaskTypes: []string{
|
|
"deployment",
|
|
"infrastructure_setup",
|
|
"ci_cd_pipeline",
|
|
"system_monitoring",
|
|
"security_configuration",
|
|
},
|
|
Priority: 5,
|
|
ContextWeight: 1.0,
|
|
FeedbackWeight: 0.4,
|
|
LearningRate: 0.1,
|
|
}
|
|
|
|
// QA role configuration
|
|
rm.roles[QARole] = &RoleConfig{
|
|
Role: QARole,
|
|
DisplayName: "Quality Assurance",
|
|
Description: "Specializes in quality assurance, code review, and process improvement",
|
|
Capabilities: []RoleCapability{
|
|
{Name: "code_review", Description: "Code review and quality assessment", Weight: 1.0},
|
|
{Name: "process_improvement", Description: "Development process improvement", Weight: 0.9},
|
|
{Name: "quality_metrics", Description: "Quality metrics and reporting", Weight: 0.8},
|
|
{Name: "best_practices", Description: "Best practices enforcement", Weight: 0.9},
|
|
{Name: "documentation", Description: "Documentation quality assurance", Weight: 0.7},
|
|
},
|
|
DirectoryScopes: DirectoryScope{
|
|
Patterns: []string{
|
|
"*/tests/*",
|
|
"*/quality/*",
|
|
"*/review/*",
|
|
"*/docs/*",
|
|
"*/documentation/*",
|
|
"*", // QA role gets broader access for review purposes
|
|
},
|
|
Description: "All directories for quality assurance and code review",
|
|
},
|
|
TaskTypes: []string{
|
|
"code_review",
|
|
"quality_assessment",
|
|
"process_improvement",
|
|
"documentation_review",
|
|
"compliance_check",
|
|
},
|
|
Priority: 4,
|
|
ContextWeight: 0.7,
|
|
FeedbackWeight: 0.5,
|
|
LearningRate: 0.2,
|
|
}
|
|
|
|
// Testing role configuration
|
|
rm.roles[TestingRole] = &RoleConfig{
|
|
Role: TestingRole,
|
|
DisplayName: "Test Engineer",
|
|
Description: "Specializes in automated testing, test frameworks, and test strategy",
|
|
Capabilities: []RoleCapability{
|
|
{Name: "unit_testing", Description: "Unit test development", Weight: 1.0},
|
|
{Name: "integration_testing", Description: "Integration test development", Weight: 0.9},
|
|
{Name: "e2e_testing", Description: "End-to-end test automation", Weight: 0.9},
|
|
{Name: "test_frameworks", Description: "Test framework setup and maintenance", Weight: 0.8},
|
|
{Name: "performance_testing", Description: "Performance and load testing", Weight: 0.7},
|
|
},
|
|
DirectoryScopes: DirectoryScope{
|
|
Patterns: []string{
|
|
"*/tests/*",
|
|
"*/spec/*",
|
|
"*/test/*",
|
|
"*/e2e/*",
|
|
"*/integration/*",
|
|
"*/__tests__/*",
|
|
"*.test.*",
|
|
"*.spec.*",
|
|
},
|
|
Description: "Test-related directories and files",
|
|
},
|
|
TaskTypes: []string{
|
|
"unit_testing",
|
|
"integration_testing",
|
|
"e2e_testing",
|
|
"test_automation",
|
|
"performance_testing",
|
|
},
|
|
Priority: 4,
|
|
ContextWeight: 0.6,
|
|
FeedbackWeight: 0.4,
|
|
LearningRate: 0.15,
|
|
}
|
|
|
|
// General role configuration
|
|
rm.roles[GeneralRole] = &RoleConfig{
|
|
Role: GeneralRole,
|
|
DisplayName: "General Developer",
|
|
Description: "General-purpose development with broad capabilities",
|
|
Capabilities: []RoleCapability{
|
|
{Name: "general_development", Description: "General software development", Weight: 0.7},
|
|
{Name: "problem_solving", Description: "General problem solving", Weight: 0.8},
|
|
{Name: "documentation", Description: "Documentation writing", Weight: 0.6},
|
|
{Name: "code_maintenance", Description: "Code maintenance and refactoring", Weight: 0.7},
|
|
{Name: "research", Description: "Technical research and analysis", Weight: 0.8},
|
|
},
|
|
DirectoryScopes: DirectoryScope{
|
|
Patterns: []string{
|
|
"*", // General role has access to all directories
|
|
},
|
|
Description: "All directories for general development tasks",
|
|
},
|
|
TaskTypes: []string{
|
|
"general_development",
|
|
"documentation",
|
|
"code_maintenance",
|
|
"research",
|
|
"bug_fixes",
|
|
},
|
|
Priority: 2,
|
|
ContextWeight: 0.5,
|
|
FeedbackWeight: 0.2,
|
|
LearningRate: 0.1,
|
|
}
|
|
}
|
|
|
|
// AssignRole assigns a role to an agent
|
|
func (rm *RoleManager) AssignRole(agentID string, role AgentRole) error {
|
|
rm.mu.Lock()
|
|
defer rm.mu.Unlock()
|
|
|
|
if _, exists := rm.roles[role]; !exists {
|
|
return fmt.Errorf("role %s does not exist", role)
|
|
}
|
|
|
|
rm.agentRoles[agentID] = role
|
|
return nil
|
|
}
|
|
|
|
// GetAgentRole returns the role assigned to an agent
|
|
func (rm *RoleManager) GetAgentRole(agentID string) (AgentRole, bool) {
|
|
rm.mu.RLock()
|
|
defer rm.mu.RUnlock()
|
|
|
|
role, exists := rm.agentRoles[agentID]
|
|
return role, exists
|
|
}
|
|
|
|
// GetRoleConfig returns the configuration for a specific role
|
|
func (rm *RoleManager) GetRoleConfig(role AgentRole) (*RoleConfig, bool) {
|
|
rm.mu.RLock()
|
|
defer rm.mu.RUnlock()
|
|
|
|
config, exists := rm.roles[role]
|
|
return config, exists
|
|
}
|
|
|
|
// GetAllRoles returns all available roles
|
|
func (rm *RoleManager) GetAllRoles() map[AgentRole]*RoleConfig {
|
|
rm.mu.RLock()
|
|
defer rm.mu.RUnlock()
|
|
|
|
result := make(map[AgentRole]*RoleConfig)
|
|
for role, config := range rm.roles {
|
|
// Create a copy to avoid race conditions
|
|
configCopy := *config
|
|
result[role] = &configCopy
|
|
}
|
|
return result
|
|
}
|
|
|
|
// MatchesDirectoryScope checks if a directory path matches the agent's scope
|
|
func (rm *RoleManager) MatchesDirectoryScope(agentID, directory string) bool {
|
|
role, exists := rm.GetAgentRole(agentID)
|
|
if !exists {
|
|
return false
|
|
}
|
|
|
|
config, exists := rm.GetRoleConfig(role)
|
|
if !exists {
|
|
return false
|
|
}
|
|
|
|
return rm.matchesPatterns(directory, config.DirectoryScopes.Patterns)
|
|
}
|
|
|
|
// GetRelevanceScore calculates context relevance score for an agent and directory
|
|
func (rm *RoleManager) GetRelevanceScore(agentID, directory string) float64 {
|
|
role, exists := rm.GetAgentRole(agentID)
|
|
if !exists {
|
|
return 0.1 // Low default score
|
|
}
|
|
|
|
config, exists := rm.GetRoleConfig(role)
|
|
if !exists {
|
|
return 0.1
|
|
}
|
|
|
|
if rm.matchesPatterns(directory, config.DirectoryScopes.Patterns) {
|
|
return config.ContextWeight
|
|
}
|
|
|
|
return 0.1 // Low score for non-matching directories
|
|
}
|
|
|
|
// matchesPatterns checks if a directory matches any of the given patterns
|
|
func (rm *RoleManager) matchesPatterns(directory string, patterns []string) bool {
|
|
if directory == "" {
|
|
return false
|
|
}
|
|
|
|
directory = strings.ToLower(directory)
|
|
|
|
for _, pattern := range patterns {
|
|
pattern = strings.ToLower(pattern)
|
|
|
|
// Handle wildcard patterns
|
|
if pattern == "*" {
|
|
return true
|
|
}
|
|
|
|
// Handle glob-style patterns
|
|
if matched, _ := filepath.Match(pattern, directory); matched {
|
|
return true
|
|
}
|
|
|
|
// Handle substring matching for directory paths
|
|
if strings.Contains(directory, strings.Trim(pattern, "*")) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// UpdateRoleWeight updates the context weight for a role (for RL learning)
|
|
func (rm *RoleManager) UpdateRoleWeight(role AgentRole, newWeight float64) error {
|
|
rm.mu.Lock()
|
|
defer rm.mu.Unlock()
|
|
|
|
config, exists := rm.roles[role]
|
|
if !exists {
|
|
return fmt.Errorf("role %s does not exist", role)
|
|
}
|
|
|
|
// Clamp weight to reasonable bounds
|
|
if newWeight < 0.1 {
|
|
newWeight = 0.1
|
|
}
|
|
if newWeight > 2.0 {
|
|
newWeight = 2.0
|
|
}
|
|
|
|
config.ContextWeight = newWeight
|
|
return nil
|
|
}
|
|
|
|
// GetAgentsByRole returns all agents assigned to a specific role
|
|
func (rm *RoleManager) GetAgentsByRole(role AgentRole) []string {
|
|
rm.mu.RLock()
|
|
defer rm.mu.RUnlock()
|
|
|
|
var agents []string
|
|
for agentID, agentRole := range rm.agentRoles {
|
|
if agentRole == role {
|
|
agents = append(agents, agentID)
|
|
}
|
|
}
|
|
return agents
|
|
}
|
|
|
|
// GetCapabilitiesForRole returns capabilities for a specific role
|
|
func (rm *RoleManager) GetCapabilitiesForRole(role AgentRole) ([]RoleCapability, bool) {
|
|
config, exists := rm.GetRoleConfig(role)
|
|
if !exists {
|
|
return nil, false
|
|
}
|
|
return config.Capabilities, true
|
|
}
|
|
|
|
// CanHandleTaskType checks if a role can handle a specific task type
|
|
func (rm *RoleManager) CanHandleTaskType(role AgentRole, taskType string) bool {
|
|
config, exists := rm.GetRoleConfig(role)
|
|
if !exists {
|
|
return false
|
|
}
|
|
|
|
for _, supportedType := range config.TaskTypes {
|
|
if supportedType == taskType {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetBestRoleForDirectory returns the best role for a given directory
|
|
func (rm *RoleManager) GetBestRoleForDirectory(directory string) (AgentRole, float64) {
|
|
bestRole := GeneralRole
|
|
bestScore := 0.0
|
|
|
|
for role, config := range rm.roles {
|
|
if rm.matchesPatterns(directory, config.DirectoryScopes.Patterns) {
|
|
score := config.ContextWeight * float64(config.Priority) / 5.0
|
|
if score > bestScore {
|
|
bestScore = score
|
|
bestRole = role
|
|
}
|
|
}
|
|
}
|
|
|
|
return bestRole, bestScore
|
|
}
|
|
|
|
// String returns string representation of AgentRole
|
|
func (ar AgentRole) String() string {
|
|
return string(ar)
|
|
}
|
|
|
|
// IsValid checks if the agent role is valid
|
|
func (ar AgentRole) IsValid() bool {
|
|
switch ar {
|
|
case BackendRole, FrontendRole, DevOpsRole, QARole, TestingRole, GeneralRole:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
} |