Skip to main content
Glama
ProblemAnalyzer.ts13.6 kB
/** * Problem Analyzer * * Analyzes problem structure, decomposes complex problems, * and identifies dependencies and priorities. */ import { IProblemAnalyzer, PriorityItem, Problem, ProblemDependency, ProblemStructure, } from "../interfaces/systematic-thinking.js"; export class ProblemAnalyzer implements IProblemAnalyzer { async initialize(): Promise<void> { // Problem analyzer is ready to use immediately } async analyzeStructure(problem: Problem): Promise<ProblemStructure> { // Decompose the main problem into sub-problems const subProblems = await this.decomposeProblem(problem); // Identify dependencies between problems const dependencies = await this.identifyDependencies([ problem, ...subProblems, ]); // Calculate critical path const criticalPath = this.calculateCriticalPath( [problem, ...subProblems], dependencies ); // Calculate priorities const priorities = await this.calculatePriorities( [problem, ...subProblems], dependencies ); return { main_problem: problem, sub_problems: subProblems, dependencies, critical_path: criticalPath, priority_ranking: priorities, }; } async decomposeProblem(problem: Problem): Promise<Problem[]> { const subProblems: Problem[] = []; // Identify decomposition patterns const decompositionStrategies = [ this.decomposeByProcess(problem), this.decomposeByComponent(problem), this.decomposeByStakeholder(problem), this.decomposeByTimePhase(problem), ]; // Apply each strategy and collect unique sub-problems for (const strategy of decompositionStrategies) { const strategyProblems = await strategy; for (const subProblem of strategyProblems) { // Avoid duplicates by checking description similarity if (!this.isDuplicateProblem(subProblem, subProblems)) { subProblems.push(subProblem); } } } // Limit to most relevant sub-problems (max 8) return subProblems.sort((a, b) => b.complexity - a.complexity).slice(0, 8); } async identifyDependencies( problems: Problem[] ): Promise<ProblemDependency[]> { const dependencies: ProblemDependency[] = []; for (let i = 0; i < problems.length; i++) { for (let j = 0; j < problems.length; j++) { if (i !== j) { const dependency = this.analyzeDependency(problems[i], problems[j]); if (dependency) { dependencies.push(dependency); } } } } return dependencies; } async calculatePriorities( problems: Problem[], dependencies: ProblemDependency[] ): Promise<PriorityItem[]> { const priorities: PriorityItem[] = []; for (const problem of problems) { const priorityScore = this.calculatePriorityScore(problem, dependencies); const reasoning = this.generatePriorityReasoning(problem, priorityScore); priorities.push({ problem_id: this.generateProblemId(problem), priority_score: priorityScore, reasoning, }); } return priorities.sort((a, b) => b.priority_score - a.priority_score); } private async decomposeByProcess(problem: Problem): Promise<Problem[]> { const subProblems: Problem[] = []; const description = problem.description.toLowerCase(); // Look for process indicators const processKeywords = [ "plan", "design", "implement", "test", "deploy", "analyze", "develop", "create", "build", "execute", "research", "prototype", "validate", "optimize", ]; for (const keyword of processKeywords) { if (description.includes(keyword)) { subProblems.push({ description: `${ keyword.charAt(0).toUpperCase() + keyword.slice(1) } phase of ${problem.description}`, domain: problem.domain, complexity: problem.complexity * 0.6, uncertainty: problem.uncertainty * 0.8, constraints: problem.constraints, stakeholders: problem.stakeholders, time_sensitivity: problem.time_sensitivity, resource_requirements: problem.resource_requirements, }); } } return subProblems; } private async decomposeByComponent(problem: Problem): Promise<Problem[]> { const subProblems: Problem[] = []; const description = problem.description.toLowerCase(); // Look for component indicators const componentPatterns = [ /frontend|ui|interface|user experience/i, /backend|server|database|api/i, /security|authentication|authorization/i, /performance|optimization|scalability/i, /testing|quality|validation/i, /documentation|training|support/i, ]; for (const pattern of componentPatterns) { if (pattern.test(description)) { const match = description.match(pattern); if (match) { subProblems.push({ description: `${match[0]} component of ${problem.description}`, domain: problem.domain, complexity: problem.complexity * 0.7, uncertainty: problem.uncertainty * 0.9, constraints: problem.constraints, stakeholders: problem.stakeholders, time_sensitivity: problem.time_sensitivity, resource_requirements: problem.resource_requirements, }); } } } return subProblems; } private async decomposeByStakeholder(problem: Problem): Promise<Problem[]> { const subProblems: Problem[] = []; // Create stakeholder-specific sub-problems for (const stakeholder of problem.stakeholders) { subProblems.push({ description: `Address ${stakeholder} requirements for ${problem.description}`, domain: problem.domain, complexity: problem.complexity * 0.5, uncertainty: problem.uncertainty * 0.7, constraints: problem.constraints, stakeholders: [stakeholder], time_sensitivity: problem.time_sensitivity, resource_requirements: problem.resource_requirements, }); } return subProblems; } private async decomposeByTimePhase(problem: Problem): Promise<Problem[]> { const subProblems: Problem[] = []; // Create time-based phases const phases = ["immediate", "short-term", "long-term"]; for (const phase of phases) { subProblems.push({ description: `${ phase.charAt(0).toUpperCase() + phase.slice(1) } solution for ${problem.description}`, domain: problem.domain, complexity: problem.complexity * (phase === "immediate" ? 0.4 : phase === "short-term" ? 0.7 : 1.0), uncertainty: problem.uncertainty * (phase === "immediate" ? 0.5 : phase === "short-term" ? 0.8 : 1.2), constraints: problem.constraints, stakeholders: problem.stakeholders, time_sensitivity: phase === "immediate" ? 1.0 : phase === "short-term" ? 0.7 : 0.3, resource_requirements: problem.resource_requirements, }); } return subProblems; } private isDuplicateProblem( problem: Problem, existingProblems: Problem[] ): boolean { const threshold = 0.95; // Similarity threshold - increased to allow more variation for (const existing of existingProblems) { const similarity = this.calculateDescriptionSimilarity( problem.description, existing.description ); if (similarity > threshold) { return true; } } return false; } private calculateDescriptionSimilarity(desc1: string, desc2: string): number { // Simple word-based similarity calculation const words1 = desc1.toLowerCase().split(/\s+/); const words2 = desc2.toLowerCase().split(/\s+/); const commonWords = words1.filter((word) => words2.includes(word)); const totalWords = new Set([...words1, ...words2]).size; return commonWords.length / totalWords; } private analyzeDependency( problem1: Problem, problem2: Problem ): ProblemDependency | null { const desc1 = problem1.description.toLowerCase(); const desc2 = problem2.description.toLowerCase(); // Check for prerequisite relationships if (this.isPrerequisite(desc1, desc2)) { return { from: this.generateProblemId(problem1), to: this.generateProblemId(problem2), type: "prerequisite", strength: 0.8, }; } // Check for constraint relationships if (this.isConstraint(problem1, problem2)) { return { from: this.generateProblemId(problem1), to: this.generateProblemId(problem2), type: "constraint", strength: 0.6, }; } // Check for resource dependencies if (this.hasResourceDependency(problem1, problem2)) { return { from: this.generateProblemId(problem1), to: this.generateProblemId(problem2), type: "resource", strength: 0.7, }; } // Check for temporal dependencies if (this.hasTemporalDependency(problem1, problem2)) { return { from: this.generateProblemId(problem1), to: this.generateProblemId(problem2), type: "temporal", strength: 0.5, }; } return null; } private isPrerequisite(desc1: string, desc2: string): boolean { const prerequisitePatterns = [ /plan.*implement/i, /design.*build/i, /research.*develop/i, /analyze.*solve/i, ]; return prerequisitePatterns.some((pattern) => { const match = `${desc1} ${desc2}`.match(pattern); return match !== null; }); } private isConstraint(problem1: Problem, problem2: Problem): boolean { // Check if problems share constraints const sharedConstraints = problem1.constraints.filter((c) => problem2.constraints.includes(c) ); return sharedConstraints.length > 0; } private hasResourceDependency(problem1: Problem, problem2: Problem): boolean { // Check if problems share resource requirements const sharedResources = problem1.resource_requirements.filter((r) => problem2.resource_requirements.includes(r) ); return sharedResources.length > 0; } private hasTemporalDependency(problem1: Problem, problem2: Problem): boolean { // Check if one problem is time-sensitive and affects the other return ( problem1.time_sensitivity > 0.7 && problem2.time_sensitivity > 0.7 && problem1.domain === problem2.domain ); } private calculateCriticalPath( problems: Problem[], dependencies: ProblemDependency[] ): string[] { // Simple critical path calculation // In a full implementation, this would use proper critical path method (CPM) const problemIds = problems.map((p) => this.generateProblemId(p)); const criticalPath: string[] = []; // Find problems with no dependencies (starting points) const noDependencies = problemIds.filter( (id) => !dependencies.some((dep) => dep.to === id) ); // Build path from starting points for (const startId of noDependencies) { criticalPath.push(startId); this.buildPathRecursive(startId, dependencies, criticalPath); } return criticalPath; } private buildPathRecursive( currentId: string, dependencies: ProblemDependency[], path: string[] ): void { const nextDependencies = dependencies.filter( (dep) => dep.from === currentId ); for (const dep of nextDependencies) { if (!path.includes(dep.to)) { path.push(dep.to); this.buildPathRecursive(dep.to, dependencies, path); } } } private calculatePriorityScore( problem: Problem, dependencies: ProblemDependency[] ): number { let score = 0.5; // Base score // Factor in complexity score += problem.complexity * 0.2; // Factor in time sensitivity score += problem.time_sensitivity * 0.3; // Factor in number of stakeholders score += (problem.stakeholders.length / 10) * 0.1; // Factor in dependency count (problems with more dependencies are higher priority) const dependencyCount = dependencies.filter( (dep) => dep.from === this.generateProblemId(problem) || dep.to === this.generateProblemId(problem) ).length; score += (dependencyCount / 10) * 0.2; // Factor in uncertainty (higher uncertainty = higher priority to resolve) score += problem.uncertainty * 0.2; return Math.min(score, 1.0); } private generatePriorityReasoning(problem: Problem, score: number): string { const reasons: string[] = []; reasons.push(`Priority score: ${(score * 100).toFixed(0)}%`); if (problem.complexity > 0.7) { reasons.push("High complexity requires early attention"); } if (problem.time_sensitivity > 0.7) { reasons.push("Time-sensitive problem needs immediate focus"); } if (problem.stakeholders.length > 2) { reasons.push("Multiple stakeholders involved"); } if (problem.uncertainty > 0.7) { reasons.push("High uncertainty needs resolution"); } return reasons.join(". "); } private generateProblemId(problem: Problem): string { // Generate a simple hash-like ID from the problem description const hash = problem.description .toLowerCase() .replace(/[^a-z0-9]/g, "") .substring(0, 20); return `problem_${hash}`; } }

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/keyurgolani/ThoughtMcp'

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