 55dd5951ea
			
		
	
	55dd5951ea
	
	
		
			
	
		
	
	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,
 | |
| 	}
 | |
| } |