refactor(analyze): Align complexity analysis with unified AI service

Refactored the  feature and related components (CLI command, MCP tool, direct function) to integrate with the unified AI service layer ().

Initially,  was implemented to leverage structured output generation. However, this approach encountered persistent errors:
- Perplexity provider returned internal server errors.
- Anthropic provider failed with schema type and model errors.

Due to the unreliability of  for this specific use case, the core AI interaction within  was reverted to use . Basic manual JSON parsing and cleanup logic for the text response were reintroduced.

Key changes include:
- Removed direct AI client initialization (Anthropic, Perplexity).
- Removed direct fetching of AI model configuration parameters.
- Removed manual AI retry/fallback/streaming logic.
- Replaced direct AI calls with a call to .
- Updated  wrapper to pass session context correctly.
- Updated  MCP tool for correct path resolution and argument passing.
- Updated  CLI command for correct path resolution.
- Preserved core functionality: task loading/filtering, report generation, CLI summary display.

Both the CLI command ([INFO] Initialized Perplexity client with OpenAI compatibility layer
[INFO] Initialized Perplexity client with OpenAI compatibility layer
Analyzing task complexity from: tasks/tasks.json
Output report will be saved to: scripts/task-complexity-report.json
Analyzing task complexity and generating expansion recommendations...
[INFO] Reading tasks from tasks/tasks.json...
[INFO] Found 62 total tasks in the task file.
[INFO] Skipping 31 tasks marked as done/cancelled/deferred. Analyzing 31 active tasks.
Skipping 31 tasks marked as done/cancelled/deferred. Analyzing 31 active tasks.
[INFO] Claude API attempt 1/2
[ERROR] Error in Claude API call: 400 {"type":"error","error":{"type":"invalid_request_error","message":"max_tokens: 100000 > 64000, which is the maximum allowed number of output tokens for claude-3-7-sonnet-20250219"}}
[ERROR] Non-overload Claude API error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"max_tokens: 100000 > 64000, which is the maximum allowed number of output tokens for claude-3-7-sonnet-20250219"}}
Claude API error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"max_tokens: 100000 > 64000, which is the maximum allowed number of output tokens for claude-3-7-sonnet-20250219"}}
[ERROR] Error during AI analysis: 400 {"type":"error","error":{"type":"invalid_request_error","message":"max_tokens: 100000 > 64000, which is the maximum allowed number of output tokens for claude-3-7-sonnet-20250219"}}
[ERROR] Error analyzing task complexity: 400 {"type":"error","error":{"type":"invalid_request_error","message":"max_tokens: 100000 > 64000, which is the maximum allowed number of output tokens for claude-3-7-sonnet-20250219"}}) and the MCP tool () have been verified to work correctly with this revised approach.
This commit is contained in:
Eyal Toledano
2025-04-24 22:33:33 -04:00
parent bec989dcc9
commit ad361f482f
7 changed files with 973 additions and 1086 deletions

View File

@@ -9,9 +9,10 @@ import {
createErrorResponse,
getProjectRootFromSession
} from './utils.js';
import { analyzeTaskComplexityDirect } from '../core/task-master-core.js';
import { analyzeTaskComplexityDirect } from '../core/direct-functions/analyze-task-complexity.js';
import { findTasksJsonPath } from '../core/utils/path-utils.js';
import path from 'path';
import fs from 'fs';
/**
* Register the analyze tool with the MCP server
@@ -27,13 +28,13 @@ export function registerAnalyzeTool(server) {
.string()
.optional()
.describe(
'Output file path for the report (default: scripts/task-complexity-report.json)'
'Output file path relative to project root (default: scripts/task-complexity-report.json)'
),
model: z
.string()
.optional()
.describe(
'LLM model to use for analysis (defaults to configured model)'
'Deprecated: LLM model override (model is determined by configured role)'
),
threshold: z.coerce
.number()
@@ -47,12 +48,13 @@ export function registerAnalyzeTool(server) {
.string()
.optional()
.describe(
'Absolute path to the tasks file (default: tasks/tasks.json)'
'Path to the tasks file relative to project root (default: tasks/tasks.json)'
),
research: z
.boolean()
.optional()
.describe('Use Perplexity AI for research-backed complexity analysis'),
.default(false)
.describe('Use research role for complexity analysis'),
projectRoot: z
.string()
.describe('The directory of the project. Must be an absolute path.')
@@ -60,17 +62,15 @@ export function registerAnalyzeTool(server) {
execute: async (args, { log, session }) => {
try {
log.info(
`Analyzing task complexity with args: ${JSON.stringify(args)}`
`Executing analyze_project_complexity tool with args: ${JSON.stringify(args)}`
);
// Get project root from args or session
const rootFolder =
args.projectRoot || getProjectRootFromSession(session, log);
const rootFolder = args.projectRoot;
if (!rootFolder) {
return createErrorResponse(
'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.'
);
return createErrorResponse('projectRoot is required.');
}
if (!path.isAbsolute(rootFolder)) {
return createErrorResponse('projectRoot must be an absolute path.');
}
let tasksJsonPath;
@@ -82,7 +82,7 @@ export function registerAnalyzeTool(server) {
} catch (error) {
log.error(`Error finding tasks.json: ${error.message}`);
return createErrorResponse(
`Failed to find tasks.json: ${error.message}`
`Failed to find tasks.json within project root '${rootFolder}': ${error.message}`
);
}
@@ -90,11 +90,25 @@ export function registerAnalyzeTool(server) {
? path.resolve(rootFolder, args.output)
: path.resolve(rootFolder, 'scripts', 'task-complexity-report.json');
const outputDir = path.dirname(outputPath);
try {
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
log.info(`Created output directory: ${outputDir}`);
}
} catch (dirError) {
log.error(
`Failed to create output directory ${outputDir}: ${dirError.message}`
);
return createErrorResponse(
`Failed to create output directory: ${dirError.message}`
);
}
const result = await analyzeTaskComplexityDirect(
{
tasksJsonPath: tasksJsonPath,
outputPath: outputPath,
model: args.model,
threshold: args.threshold,
research: args.research
},
@@ -103,20 +117,17 @@ export function registerAnalyzeTool(server) {
);
if (result.success) {
log.info(`Task complexity analysis complete: ${result.data.message}`);
log.info(
`Report summary: ${JSON.stringify(result.data.reportSummary)}`
);
log.info(`Tool analyze_project_complexity finished successfully.`);
} else {
log.error(
`Failed to analyze task complexity: ${result.error.message}`
`Tool analyze_project_complexity failed: ${result.error?.message || 'Unknown error'}`
);
}
return handleApiResult(result, log, 'Error analyzing task complexity');
} catch (error) {
log.error(`Error in analyze tool: ${error.message}`);
return createErrorResponse(error.message);
log.error(`Critical error in analyze tool execute: ${error.message}`);
return createErrorResponse(`Internal tool error: ${error.message}`);
}
}
});