Resolves WHOOSH-LLM-002: Replace stubbed LLM functions with full Ollama API integration ## New Features - Full Ollama API integration with automatic endpoint discovery - LLM-powered task classification using configurable models - LLM-powered skill requirement analysis - Graceful fallback to heuristics on LLM failures - Feature flag support for LLM vs heuristic execution - Performance optimization with smaller, faster models (llama3.2:latest) ## Implementation Details - Created OllamaClient with connection pooling and timeout handling - Structured prompt engineering for consistent JSON responses - Robust error handling with automatic failover to heuristics - Comprehensive integration tests validating functionality - Support for multiple Ollama endpoints with health checking ## Performance & Reliability - Timeout configuration prevents hanging requests - Fallback mechanism ensures system reliability - Uses 3.2B parameter model for balance of speed vs accuracy - Graceful degradation when LLM services unavailable ## Files Added - internal/composer/ollama.go: Core Ollama API integration - internal/composer/llm_test.go: Comprehensive integration tests ## Files Modified - internal/composer/service.go: Implemented LLM functions - internal/composer/models.go: Updated config for performance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
250 lines
9.8 KiB
Go
250 lines
9.8 KiB
Go
package composer
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// TaskPriority represents task priority levels
|
|
type TaskPriority string
|
|
|
|
const (
|
|
PriorityLow TaskPriority = "low"
|
|
PriorityMedium TaskPriority = "medium"
|
|
PriorityHigh TaskPriority = "high"
|
|
PriorityCritical TaskPriority = "critical"
|
|
)
|
|
|
|
// TaskType represents different types of development tasks
|
|
type TaskType string
|
|
|
|
const (
|
|
TaskTypeFeatureDevelopment TaskType = "feature_development"
|
|
TaskTypeBugFix TaskType = "bug_fix"
|
|
TaskTypeRefactoring TaskType = "refactoring"
|
|
TaskTypeMigration TaskType = "migration"
|
|
TaskTypeResearch TaskType = "research"
|
|
TaskTypeOptimization TaskType = "optimization"
|
|
TaskTypeSecurity TaskType = "security"
|
|
TaskTypeIntegration TaskType = "integration"
|
|
TaskTypeMaintenance TaskType = "maintenance"
|
|
)
|
|
|
|
// AgentStatus represents the current status of an agent
|
|
type AgentStatus string
|
|
|
|
const (
|
|
AgentStatusAvailable AgentStatus = "available"
|
|
AgentStatusBusy AgentStatus = "busy"
|
|
AgentStatusOffline AgentStatus = "offline"
|
|
AgentStatusIdle AgentStatus = "idle"
|
|
)
|
|
|
|
// TeamStatus represents the current status of a team
|
|
type TeamStatus string
|
|
|
|
const (
|
|
TeamStatusForming TeamStatus = "forming"
|
|
TeamStatusActive TeamStatus = "active"
|
|
TeamStatusCompleted TeamStatus = "completed"
|
|
TeamStatusDisbanded TeamStatus = "disbanded"
|
|
)
|
|
|
|
// TaskAnalysisInput represents the input data for team composition analysis
|
|
type TaskAnalysisInput struct {
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
Requirements []string `json:"requirements"`
|
|
Repository string `json:"repository,omitempty"`
|
|
Priority TaskPriority `json:"priority"`
|
|
TechStack []string `json:"tech_stack,omitempty"`
|
|
EstimatedHours int `json:"estimated_hours,omitempty"`
|
|
Complexity float64 `json:"complexity,omitempty"`
|
|
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
|
}
|
|
|
|
// TaskClassification represents the result of task classification analysis
|
|
type TaskClassification struct {
|
|
TaskType TaskType `json:"task_type"`
|
|
ComplexityScore float64 `json:"complexity_score"`
|
|
PrimaryDomains []string `json:"primary_domains"`
|
|
SecondaryDomains []string `json:"secondary_domains"`
|
|
EstimatedDuration int `json:"estimated_duration_hours"`
|
|
RiskLevel string `json:"risk_level"`
|
|
RequiredExperience string `json:"required_experience"`
|
|
}
|
|
|
|
// SkillRequirement represents a required skill with proficiency level
|
|
type SkillRequirement struct {
|
|
Domain string `json:"domain"`
|
|
MinProficiency float64 `json:"min_proficiency"`
|
|
Weight float64 `json:"weight"`
|
|
Critical bool `json:"critical"`
|
|
}
|
|
|
|
// SkillRequirements represents the complete skill analysis for a task
|
|
type SkillRequirements struct {
|
|
CriticalSkills []SkillRequirement `json:"critical_skills"`
|
|
DesirableSkills []SkillRequirement `json:"desirable_skills"`
|
|
TotalSkillCount int `json:"total_skill_count"`
|
|
}
|
|
|
|
// Agent represents an available AI agent with capabilities
|
|
type Agent struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
Name string `json:"name" db:"name"`
|
|
EndpointURL string `json:"endpoint_url" db:"endpoint_url"`
|
|
Capabilities map[string]interface{} `json:"capabilities" db:"capabilities"`
|
|
Status AgentStatus `json:"status" db:"status"`
|
|
LastSeen time.Time `json:"last_seen" db:"last_seen"`
|
|
PerformanceMetrics map[string]interface{} `json:"performance_metrics" db:"performance_metrics"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
}
|
|
|
|
// TeamRole represents a role that can be assigned within a team
|
|
type TeamRole struct {
|
|
ID int `json:"id" db:"id"`
|
|
Name string `json:"name" db:"name"`
|
|
Description string `json:"description" db:"description"`
|
|
Capabilities map[string]interface{} `json:"capabilities" db:"capabilities"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
}
|
|
|
|
// Team represents a composed development team
|
|
type Team struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
Name string `json:"name" db:"name"`
|
|
Description string `json:"description" db:"description"`
|
|
Status TeamStatus `json:"status" db:"status"`
|
|
TaskID *uuid.UUID `json:"task_id,omitempty" db:"task_id"`
|
|
GiteaIssueURL string `json:"gitea_issue_url,omitempty" db:"gitea_issue_url"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
CompletedAt *time.Time `json:"completed_at,omitempty" db:"completed_at"`
|
|
}
|
|
|
|
// TeamAssignment represents an agent assigned to a team role
|
|
type TeamAssignment struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
TeamID uuid.UUID `json:"team_id" db:"team_id"`
|
|
AgentID uuid.UUID `json:"agent_id" db:"agent_id"`
|
|
RoleID int `json:"role_id" db:"role_id"`
|
|
Status string `json:"status" db:"status"`
|
|
AssignedAt time.Time `json:"assigned_at" db:"assigned_at"`
|
|
CompletedAt *time.Time `json:"completed_at,omitempty" db:"completed_at"`
|
|
}
|
|
|
|
// AgentMatch represents how well an agent matches a role requirement
|
|
type AgentMatch struct {
|
|
Agent *Agent `json:"agent"`
|
|
Role *TeamRole `json:"role"`
|
|
OverallScore float64 `json:"overall_score"`
|
|
SkillScore float64 `json:"skill_score"`
|
|
AvailabilityScore float64 `json:"availability_score"`
|
|
ExperienceScore float64 `json:"experience_score"`
|
|
Reasoning string `json:"reasoning"`
|
|
Confidence float64 `json:"confidence"`
|
|
}
|
|
|
|
// TeamComposition represents the recommended team structure
|
|
type TeamComposition struct {
|
|
TeamID uuid.UUID `json:"team_id"`
|
|
Name string `json:"name"`
|
|
Strategy string `json:"strategy"`
|
|
RequiredRoles []*TeamRole `json:"required_roles"`
|
|
OptionalRoles []*TeamRole `json:"optional_roles"`
|
|
AgentMatches []*AgentMatch `json:"agent_matches"`
|
|
EstimatedSize int `json:"estimated_size"`
|
|
ConfidenceScore float64 `json:"confidence_score"`
|
|
}
|
|
|
|
// CompositionResult represents the complete result of team composition analysis
|
|
type CompositionResult struct {
|
|
AnalysisID uuid.UUID `json:"analysis_id"`
|
|
TaskInput *TaskAnalysisInput `json:"task_input"`
|
|
Classification *TaskClassification `json:"classification"`
|
|
SkillRequirements *SkillRequirements `json:"skill_requirements"`
|
|
TeamComposition *TeamComposition `json:"team_composition"`
|
|
AlternativeOptions []*TeamComposition `json:"alternative_options,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
ProcessingTimeMs int64 `json:"processing_time_ms"`
|
|
}
|
|
|
|
// ComposerConfig represents configuration for the team composer
|
|
type ComposerConfig struct {
|
|
// Model selection for different analysis types
|
|
ClassificationModel string `json:"classification_model"`
|
|
SkillAnalysisModel string `json:"skill_analysis_model"`
|
|
MatchingModel string `json:"matching_model"`
|
|
|
|
// Composition strategy settings
|
|
DefaultStrategy string `json:"default_strategy"`
|
|
MinTeamSize int `json:"min_team_size"`
|
|
MaxTeamSize int `json:"max_team_size"`
|
|
SkillMatchThreshold float64 `json:"skill_match_threshold"`
|
|
|
|
// Performance settings
|
|
AnalysisTimeoutSecs int `json:"analysis_timeout_secs"`
|
|
EnableCaching bool `json:"enable_caching"`
|
|
CacheTTLMins int `json:"cache_ttl_mins"`
|
|
|
|
// Feature flags
|
|
FeatureFlags FeatureFlags `json:"feature_flags"`
|
|
}
|
|
|
|
// FeatureFlags controls experimental and optional features in the composer
|
|
type FeatureFlags struct {
|
|
// LLM-based analysis (vs heuristic-based)
|
|
EnableLLMClassification bool `json:"enable_llm_classification"`
|
|
EnableLLMSkillAnalysis bool `json:"enable_llm_skill_analysis"`
|
|
EnableLLMTeamMatching bool `json:"enable_llm_team_matching"`
|
|
|
|
// Advanced analysis features
|
|
EnableComplexityAnalysis bool `json:"enable_complexity_analysis"`
|
|
EnableRiskAssessment bool `json:"enable_risk_assessment"`
|
|
EnableAlternativeOptions bool `json:"enable_alternative_options"`
|
|
|
|
// Performance and debugging
|
|
EnableAnalysisLogging bool `json:"enable_analysis_logging"`
|
|
EnablePerformanceMetrics bool `json:"enable_performance_metrics"`
|
|
EnableFailsafeFallback bool `json:"enable_failsafe_fallback"`
|
|
}
|
|
|
|
// DefaultComposerConfig returns sensible defaults for MVP
|
|
func DefaultComposerConfig() *ComposerConfig {
|
|
return &ComposerConfig{
|
|
ClassificationModel: "llama3.2:latest", // Smaller 3.2B model for faster response
|
|
SkillAnalysisModel: "llama3.2:latest", // Smaller 3.2B model for faster response
|
|
MatchingModel: "llama3.2:latest", // Smaller 3.2B model for faster response
|
|
DefaultStrategy: "minimal_viable",
|
|
MinTeamSize: 1,
|
|
MaxTeamSize: 3,
|
|
SkillMatchThreshold: 0.6,
|
|
AnalysisTimeoutSecs: 30, // Reduced timeout for faster failover
|
|
EnableCaching: true,
|
|
CacheTTLMins: 30,
|
|
FeatureFlags: DefaultFeatureFlags(),
|
|
}
|
|
}
|
|
|
|
// DefaultFeatureFlags returns conservative defaults that prioritize reliability
|
|
func DefaultFeatureFlags() FeatureFlags {
|
|
return FeatureFlags{
|
|
// LLM features disabled by default - use heuristics for reliability
|
|
EnableLLMClassification: false,
|
|
EnableLLMSkillAnalysis: false,
|
|
EnableLLMTeamMatching: false,
|
|
|
|
// Basic analysis features enabled
|
|
EnableComplexityAnalysis: true,
|
|
EnableRiskAssessment: true,
|
|
EnableAlternativeOptions: false, // Disabled for MVP performance
|
|
|
|
// Debug and monitoring enabled
|
|
EnableAnalysisLogging: true,
|
|
EnablePerformanceMetrics: true,
|
|
EnableFailsafeFallback: true,
|
|
}
|
|
} |