Add subtask generation decision
Change-Id: If43efa882de08bc262fe6117af7307e97c4dfeda
diff --git a/server/subtasks/service_test.go b/server/subtasks/service_test.go
index 1d94211..ade62fc 100644
--- a/server/subtasks/service_test.go
+++ b/server/subtasks/service_test.go
@@ -95,6 +95,38 @@
}
}
+func TestShouldGenerateSubtasks(t *testing.T) {
+ // Test decision to generate subtasks
+ decisionResponse := `{
+ "needs_subtasks": true,
+ "reasoning": "Complex task requiring multiple skills",
+ "complexity_score": 8,
+ "required_skills": ["backend", "frontend", "database"]
+}`
+
+ mockProvider := NewMockLLMProvider([]string{decisionResponse})
+ agentRoles := []string{"backend", "frontend", "qa"}
+ service := NewSubtaskService(mockProvider, nil, agentRoles)
+
+ // Test the parseSubtaskDecision method directly since ShouldGenerateSubtasks is used by manager
+ decision, err := service.parseSubtaskDecision(decisionResponse)
+ if err != nil {
+ t.Fatalf("parseSubtaskDecision failed: %v", err)
+ }
+
+ if !decision.NeedsSubtasks {
+ t.Error("Expected decision to need subtasks")
+ }
+
+ if decision.ComplexityScore != 8 {
+ t.Errorf("Expected complexity score 8, got %d", decision.ComplexityScore)
+ }
+
+ if len(decision.RequiredSkills) != 3 {
+ t.Errorf("Expected 3 required skills, got %d", len(decision.RequiredSkills))
+ }
+}
+
func TestAnalyzeTaskForSubtasks(t *testing.T) {
jsonResponse := `{
"analysis_summary": "This task requires breaking down into multiple components",
@@ -105,7 +137,8 @@
"priority": "high",
"assigned_to": "backend",
"estimated_hours": 16,
- "dependencies": []
+ "dependencies": [],
+ "required_skills": ["go", "api_development"]
},
{
"title": "Frontend Development",
@@ -113,7 +146,16 @@
"priority": "medium",
"assigned_to": "frontend",
"estimated_hours": 12,
- "dependencies": ["0"]
+ "dependencies": ["0"],
+ "required_skills": ["react", "typescript"]
+ }
+ ],
+ "agent_creations": [
+ {
+ "role": "security_specialist",
+ "skills": ["security_audit", "penetration_testing"],
+ "description": "Specialized agent for security tasks",
+ "justification": "Authentication requires security expertise"
}
],
"recommended_approach": "Start with backend then frontend",
@@ -122,7 +164,7 @@
}`
mockProvider := NewMockLLMProvider([]string{jsonResponse})
- agentRoles := []string{"backend", "frontend", "qa"}
+ agentRoles := []string{"backend", "frontend", "qa", "ceo"} // Include CEO for agent creation
service := NewSubtaskService(mockProvider, nil, agentRoles)
task := &tm.Task{
@@ -148,12 +190,39 @@
t.Error("Analysis summary should not be empty")
}
- if len(analysis.Subtasks) != 2 {
- t.Errorf("Expected 2 subtasks, got %d", len(analysis.Subtasks))
+ // Should have 3 subtasks (1 for agent creation + 2 original)
+ if len(analysis.Subtasks) != 3 {
+ t.Errorf("Expected 3 subtasks (including agent creation), got %d", len(analysis.Subtasks))
+ t.Logf("Subtasks: %+v", analysis.Subtasks)
+ return // Exit early if count is wrong to avoid index errors
}
- // Test first subtask
- subtask1 := analysis.Subtasks[0]
+ // Test agent creation was processed
+ if len(analysis.AgentCreations) != 1 {
+ t.Errorf("Expected 1 agent creation, got %d", len(analysis.AgentCreations))
+ } else {
+ agentCreation := analysis.AgentCreations[0]
+ if agentCreation.Role != "security_specialist" {
+ t.Errorf("Expected role 'security_specialist', got %s", agentCreation.Role)
+ }
+ if len(agentCreation.Skills) != 2 {
+ t.Errorf("Expected 2 skills, got %d", len(agentCreation.Skills))
+ }
+ }
+
+ // We already checked the count above
+
+ // Test first subtask (agent creation)
+ subtask0 := analysis.Subtasks[0]
+ if !strings.Contains(subtask0.Title, "Security_specialist") {
+ t.Errorf("Expected agent creation subtask for security_specialist, got %s", subtask0.Title)
+ }
+ if subtask0.AssignedTo != "ceo" {
+ t.Errorf("Expected agent creation assigned to 'ceo', got %s", subtask0.AssignedTo)
+ }
+
+ // Test second subtask (original backend task, now at index 1)
+ subtask1 := analysis.Subtasks[1]
if subtask1.Title != "Backend Development" {
t.Errorf("Expected title 'Backend Development', got %s", subtask1.Title)
}
@@ -166,19 +235,27 @@
if subtask1.EstimatedHours != 16 {
t.Errorf("Expected 16 hours, got %d", subtask1.EstimatedHours)
}
+ if len(subtask1.RequiredSkills) != 2 {
+ t.Errorf("Expected 2 required skills, got %d", len(subtask1.RequiredSkills))
+ }
- // Test second subtask
- subtask2 := analysis.Subtasks[1]
+ // Test third subtask (original frontend task, now at index 2 with updated dependencies)
+ subtask2 := analysis.Subtasks[2]
if subtask2.Title != "Frontend Development" {
t.Errorf("Expected title 'Frontend Development', got %s", subtask2.Title)
}
if subtask2.Priority != tm.PriorityMedium {
t.Errorf("Expected medium priority, got %s", subtask2.Priority)
}
- if len(subtask2.Dependencies) != 1 || subtask2.Dependencies[0] != "0" {
- t.Errorf("Expected dependencies [0], got %v", subtask2.Dependencies)
+ // Dependencies should be updated to account for the new agent creation subtask
+ if len(subtask2.Dependencies) != 1 || subtask2.Dependencies[0] != "1" {
+ t.Errorf("Expected dependencies [1] (updated for agent creation), got %v", subtask2.Dependencies)
+ }
+ if len(subtask2.RequiredSkills) != 2 {
+ t.Errorf("Expected 2 required skills, got %d", len(subtask2.RequiredSkills))
}
+ // Total hours should include agent creation time (4 hours)
if analysis.EstimatedTotalHours != 28 {
t.Errorf("Expected 28 total hours, got %d", analysis.EstimatedTotalHours)
}