Skip to main content
Glama
analyzePrompt.ts7 kB
/** * Analyze Prompt Tool * Evaluates prompt quality and provides improvement suggestions * Uses PromptArchitect API with local fallback */ import { z } from 'zod'; import { logger, apiAnalyzePrompt, isApiClientAvailable, } from '../utils/index.js'; export const analyzePromptSchema = z.object({ prompt: z.string().min(1).describe('The prompt to analyze'), evaluationCriteria: z.array(z.string()).optional().describe('Specific criteria to evaluate'), }); export type AnalyzePromptInput = z.infer<typeof analyzePromptSchema>; export interface AnalysisResult { scores: { overall: number; clarity: number; specificity: number; structure: number; actionability: number; }; suggestions: string[]; strengths: string[]; weaknesses: string[]; metadata: { wordCount: number; sentenceCount: number; hasStructure: boolean; hasExamples: boolean; hasConstraints: boolean; }; } const DEFAULT_CRITERIA = [ 'clarity', 'specificity', 'structure', 'actionability', ]; export async function analyzePrompt(input: AnalyzePromptInput): Promise<AnalysisResult> { const { prompt, evaluationCriteria = DEFAULT_CRITERIA } = input; logger.info('Analyzing prompt', { promptLength: prompt.length, criteria: evaluationCriteria }); // Calculate structural metadata (always needed) const metadata = calculateMetadata(prompt); // Use PromptArchitect API if (isApiClientAvailable()) { try { const response = await apiAnalyzePrompt({ prompt, evaluationCriteria, }); logger.info('Analyzed via PromptArchitect API'); return { scores: { overall: response.overallScore, clarity: response.scores.clarity, specificity: response.scores.specificity, structure: response.scores.structure, actionability: response.scores.actionability, }, suggestions: response.suggestions || [], strengths: response.strengths || identifyStrengths(prompt, metadata), weaknesses: response.weaknesses || identifyWeaknesses(prompt, metadata), metadata, }; } catch (error) { logger.warn('API request failed, using fallback', { error: error instanceof Error ? error.message : 'Unknown error' }); } } // Fallback rule-based analysis logger.warn('Using fallback rule-based analysis'); return performRuleBasedAnalysis(prompt, metadata); } function calculateMetadata(prompt: string): AnalysisResult['metadata'] { const words = prompt.split(/\s+/).filter(w => w.length > 0); const sentences = prompt.split(/[.!?]+/).filter(s => s.trim().length > 0); return { wordCount: words.length, sentenceCount: sentences.length, hasStructure: /^#+\s|^\d+\.|^-\s|^\*\s|\[|\]/m.test(prompt), hasExamples: /example|e\.g\.|for instance|such as|like this/i.test(prompt), hasConstraints: /must|should|avoid|don't|do not|never|always|required/i.test(prompt), }; } function identifyStrengths(prompt: string, metadata: AnalysisResult['metadata']): string[] { const strengths: string[] = []; if (metadata.hasStructure) { strengths.push('Well-structured with clear sections or formatting'); } if (metadata.hasExamples) { strengths.push('Includes examples for clarity'); } if (metadata.hasConstraints) { strengths.push('Provides clear constraints and requirements'); } if (metadata.wordCount >= 50 && metadata.wordCount <= 500) { strengths.push('Appropriate length - detailed but not overwhelming'); } if (/^(you are|act as|pretend to be)/i.test(prompt)) { strengths.push('Uses role-based framing'); } if (/output|response|format|result/i.test(prompt)) { strengths.push('Specifies expected output format'); } return strengths.length > 0 ? strengths : ['Prompt is functional and clear']; } function identifyWeaknesses(prompt: string, metadata: AnalysisResult['metadata']): string[] { const weaknesses: string[] = []; if (!metadata.hasStructure && metadata.wordCount > 100) { weaknesses.push('Long prompt without clear structure'); } if (!metadata.hasExamples && metadata.wordCount > 50) { weaknesses.push('Could benefit from examples'); } if (metadata.wordCount < 20) { weaknesses.push('Very short - may lack necessary context'); } if (!/[?]/.test(prompt) && !/^(create|generate|write|explain|list)/i.test(prompt)) { weaknesses.push('Unclear what action is expected'); } if ((prompt.match(/\n/g) || []).length === 0 && metadata.wordCount > 50) { weaknesses.push('Dense single block - consider breaking into sections'); } return weaknesses; } function performRuleBasedAnalysis(prompt: string, metadata: AnalysisResult['metadata']): AnalysisResult { // Calculate scores based on heuristics let clarityScore = 70; let specificityScore = 60; let structureScore = 50; let actionabilityScore = 65; // Clarity adjustments const avgSentenceLength = prompt.length / (metadata.sentenceCount || 1); if (avgSentenceLength < 100) clarityScore += 10; if (avgSentenceLength > 200) clarityScore -= 15; // Specificity adjustments if (metadata.hasExamples) specificityScore += 15; if (metadata.hasConstraints) specificityScore += 10; // Structure adjustments if (metadata.hasStructure) structureScore += 30; if (metadata.wordCount > 100 && !metadata.hasStructure) structureScore -= 20; // Actionability adjustments if (/^(create|generate|write|analyze|explain|list|describe|build)/i.test(prompt)) { actionabilityScore += 15; } if (/output|response|format|result/i.test(prompt)) { actionabilityScore += 10; } // Clamp all scores const clamp = (n: number) => Math.max(0, Math.min(100, n)); clarityScore = clamp(clarityScore); specificityScore = clamp(specificityScore); structureScore = clamp(structureScore); actionabilityScore = clamp(actionabilityScore); const overall = Math.round((clarityScore + specificityScore + structureScore + actionabilityScore) / 4); // Generate suggestions const suggestions: string[] = []; if (structureScore < 60) suggestions.push('Add headers or bullet points to organize the prompt'); if (specificityScore < 60) suggestions.push('Include more specific details or examples'); if (actionabilityScore < 70) suggestions.push('Start with a clear action verb (Create, Generate, Write, etc.)'); if (clarityScore < 70) suggestions.push('Break long sentences into shorter, clearer ones'); if (!metadata.hasExamples) suggestions.push('Add an example of expected output'); return { scores: { overall, clarity: clarityScore, specificity: specificityScore, structure: structureScore, actionability: actionabilityScore, }, suggestions: suggestions.slice(0, 5), strengths: identifyStrengths(prompt, metadata), weaknesses: identifyWeaknesses(prompt, metadata), metadata, }; } export default analyzePrompt;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MerabyLabs/promptarchitect-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server