fix(expand-task): include parent task context in complexity report variant (#1094)
- Fixed bug where expand task generated generic authentication subtasks - The complexity-report prompt variant now includes parent task details - Added comprehensive unit tests to prevent regression - Added debug logging to help diagnose similar issues Previously, when using a complexity report with expansionPrompt, only the expansion guidance was sent to the AI, missing the actual task context. This caused the AI to generate unrelated generic subtasks. Fixes the issue where all tasks would get the same generic auth-related subtasks regardless of their actual purpose (AWS infrastructure, Docker containerization, etc.) Co-authored-by: Sadaqat Ali <32377500+sadaqat12@users.noreply.github.com>
This commit is contained in:
7
.changeset/fuzzy-brooms-mate.md
Normal file
7
.changeset/fuzzy-brooms-mate.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"task-master-ai": patch
|
||||
---
|
||||
|
||||
Fix expand task generating unrelated generic subtasks
|
||||
|
||||
Fixed an issue where `task-master expand` would generate generic authentication-related subtasks regardless of the parent task context when using complexity reports. The expansion now properly includes the parent task details alongside any expansion guidance.
|
||||
@@ -527,6 +527,18 @@ async function expandTask(
|
||||
|
||||
const { systemPrompt, userPrompt: promptContent } =
|
||||
await promptManager.loadPrompt('expand-task', promptParams, variantKey);
|
||||
|
||||
// Debug logging to identify the issue
|
||||
logger.debug(`Selected variant: ${variantKey}`);
|
||||
logger.debug(
|
||||
`Prompt params passed: ${JSON.stringify(promptParams, null, 2)}`
|
||||
);
|
||||
logger.debug(
|
||||
`System prompt (first 500 chars): ${systemPrompt.substring(0, 500)}...`
|
||||
);
|
||||
logger.debug(
|
||||
`User prompt (first 500 chars): ${promptContent.substring(0, 500)}...`
|
||||
);
|
||||
// --- End Complexity Report / Prompt Logic ---
|
||||
|
||||
// --- AI Subtask Generation using generateTextService ---
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
"complexity-report": {
|
||||
"condition": "expansionPrompt",
|
||||
"system": "You are an AI assistant helping with task breakdown. Generate {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks based on the provided prompt and context.\nRespond ONLY with a valid JSON object containing a single key \"subtasks\" whose value is an array of the generated subtask objects.\nEach subtask object in the array must have keys: \"id\", \"title\", \"description\", \"dependencies\", \"details\", \"status\".\nEnsure the 'id' starts from {{nextSubtaskId}} and is sequential.\nFor 'dependencies', use the full subtask ID format: \"{{task.id}}.1\", \"{{task.id}}.2\", etc. Only reference subtasks within this same task.\nEnsure 'status' is 'pending'.\nDo not include any other text or explanation.",
|
||||
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating subtasks:\n\n1. Use the Glob tool to explore relevant files for this task (e.g., \"**/*.js\", \"src/**/*.ts\")\n2. Use the Grep tool to search for existing implementations related to this task\n3. Use the Read tool to examine files that would be affected by this task\n4. Understand the current implementation state and patterns used\n\nBased on your analysis:\n- Identify existing code that relates to this task\n- Understand patterns and conventions to follow\n- Generate subtasks that integrate smoothly with existing code\n- Ensure subtasks are specific and actionable based on the actual codebase\n\nProject Root: {{projectRoot}}\n\n{{/if}}{{expansionPrompt}}{{#if additionalContext}}\n\n{{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\n\n{{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}"
|
||||
"user": "Break down the following task based on the analysis prompt:\n\nParent Task:\nID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}\n\nExpansion Guidance:\n{{expansionPrompt}}{{#if additionalContext}}\n\n{{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\n\n{{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nGenerate {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks with sequential IDs starting from {{nextSubtaskId}}."
|
||||
},
|
||||
"research": {
|
||||
"condition": "useResearch === true && !expansionPrompt",
|
||||
|
||||
134
tests/unit/prompts/expand-task-prompt.test.js
Normal file
134
tests/unit/prompts/expand-task-prompt.test.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import { jest } from '@jest/globals';
|
||||
import { PromptManager } from '../../../scripts/modules/prompt-manager.js';
|
||||
|
||||
describe('expand-task prompt template', () => {
|
||||
let promptManager;
|
||||
|
||||
beforeEach(() => {
|
||||
promptManager = new PromptManager();
|
||||
});
|
||||
|
||||
const testTask = {
|
||||
id: 1,
|
||||
title: 'Setup AWS Infrastructure',
|
||||
description: 'Provision core AWS services',
|
||||
details: 'Create VPC, subnets, and security groups'
|
||||
};
|
||||
|
||||
const baseParams = {
|
||||
task: testTask,
|
||||
subtaskCount: 3,
|
||||
nextSubtaskId: 1,
|
||||
additionalContext: '',
|
||||
complexityReasoningContext: '',
|
||||
gatheredContext: '',
|
||||
useResearch: false,
|
||||
expansionPrompt: undefined
|
||||
};
|
||||
|
||||
test('default variant includes task context', () => {
|
||||
const { userPrompt } = promptManager.loadPrompt(
|
||||
'expand-task',
|
||||
baseParams,
|
||||
'default'
|
||||
);
|
||||
|
||||
expect(userPrompt).toContain(testTask.title);
|
||||
expect(userPrompt).toContain(testTask.description);
|
||||
expect(userPrompt).toContain(testTask.details);
|
||||
expect(userPrompt).toContain('Task ID: 1');
|
||||
});
|
||||
|
||||
test('research variant includes task context', () => {
|
||||
const params = { ...baseParams, useResearch: true };
|
||||
const { userPrompt } = promptManager.loadPrompt(
|
||||
'expand-task',
|
||||
params,
|
||||
'research'
|
||||
);
|
||||
|
||||
expect(userPrompt).toContain(testTask.title);
|
||||
expect(userPrompt).toContain(testTask.description);
|
||||
expect(userPrompt).toContain(testTask.details);
|
||||
expect(userPrompt).toContain('Parent Task:');
|
||||
expect(userPrompt).toContain('ID: 1');
|
||||
});
|
||||
|
||||
test('complexity-report variant includes task context', () => {
|
||||
const params = {
|
||||
...baseParams,
|
||||
expansionPrompt: 'Focus on security best practices',
|
||||
complexityReasoningContext: 'High complexity due to security requirements'
|
||||
};
|
||||
const { userPrompt } = promptManager.loadPrompt(
|
||||
'expand-task',
|
||||
params,
|
||||
'complexity-report'
|
||||
);
|
||||
|
||||
// The fix ensures task context is included
|
||||
expect(userPrompt).toContain('Parent Task:');
|
||||
expect(userPrompt).toContain(`ID: ${testTask.id}`);
|
||||
expect(userPrompt).toContain(`Title: ${testTask.title}`);
|
||||
expect(userPrompt).toContain(`Description: ${testTask.description}`);
|
||||
expect(userPrompt).toContain(`Current details: ${testTask.details}`);
|
||||
|
||||
// Also includes the expansion prompt
|
||||
expect(userPrompt).toContain('Expansion Guidance:');
|
||||
expect(userPrompt).toContain(params.expansionPrompt);
|
||||
expect(userPrompt).toContain(params.complexityReasoningContext);
|
||||
});
|
||||
|
||||
test('all variants request JSON format with subtasks array', () => {
|
||||
const variants = ['default', 'research', 'complexity-report'];
|
||||
|
||||
variants.forEach((variant) => {
|
||||
const params =
|
||||
variant === 'complexity-report'
|
||||
? { ...baseParams, expansionPrompt: 'test' }
|
||||
: baseParams;
|
||||
|
||||
const { systemPrompt, userPrompt } = promptManager.loadPrompt(
|
||||
'expand-task',
|
||||
params,
|
||||
variant
|
||||
);
|
||||
const combined = systemPrompt + userPrompt;
|
||||
|
||||
expect(combined.toLowerCase()).toContain('subtasks');
|
||||
expect(combined).toContain('JSON');
|
||||
});
|
||||
});
|
||||
|
||||
test('complexity-report variant fails without task context regression test', () => {
|
||||
// This test ensures we don't regress to the old behavior where
|
||||
// complexity-report variant only used expansionPrompt without task context
|
||||
const params = {
|
||||
...baseParams,
|
||||
expansionPrompt: 'Generic expansion prompt'
|
||||
};
|
||||
|
||||
const { userPrompt } = promptManager.loadPrompt(
|
||||
'expand-task',
|
||||
params,
|
||||
'complexity-report'
|
||||
);
|
||||
|
||||
// Count occurrences of task-specific content
|
||||
const titleOccurrences = (
|
||||
userPrompt.match(new RegExp(testTask.title, 'g')) || []
|
||||
).length;
|
||||
const descriptionOccurrences = (
|
||||
userPrompt.match(new RegExp(testTask.description, 'g')) || []
|
||||
).length;
|
||||
|
||||
// Should have at least one occurrence of title and description
|
||||
expect(titleOccurrences).toBeGreaterThanOrEqual(1);
|
||||
expect(descriptionOccurrences).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// Should not be ONLY the expansion prompt
|
||||
expect(userPrompt.length).toBeGreaterThan(
|
||||
params.expansionPrompt.length + 100
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user