UNPKG

@emmahyde/thinking-patterns

Version:

MCP server combining systematic thinking, mental models, debugging approaches, and stochastic algorithms for comprehensive cognitive pattern support

147 lines (146 loc) 5.62 kB
import { BaseToolServer } from '../base/BaseToolServer.js'; import { MentalModelSchema } from '../schemas/index.js'; import { boxed } from '../utils/index.js'; /** * Mental Model Server using thinking-patterns tools approach * Extends BaseToolServer for standardized validation and error handling */ export class MentalModelServer extends BaseToolServer { constructor() { super(MentalModelSchema); } handle(validInput) { return this.process(validInput); } /** * Standardized process method for mental model * @param validInput - Validated mental model data * @returns Processed mental model result */ process(validInput) { // Format output using boxed utility const formattedOutput = this.formatMentalModelOutput(validInput); // Log formatted output to console (suppress during tests) if (process.env.NODE_ENV !== 'test' && process.env.JEST_WORKER_ID === undefined) { console.error(formattedOutput); } const analysis = this.analyze(validInput); return { modelName: validInput.modelName, problem: validInput.problem, steps: validInput.steps, reasoning: validInput.reasoning, conclusion: validInput.conclusion, analysis: { status: 'success', timestamp: new Date().toISOString(), quality: analysis.quality, complexity: analysis.complexity, keywords: analysis.keywords, suggestions: analysis.suggestions, }, summary: { hasSteps: (validInput.steps?.length ?? 0) > 0, hasReasoning: !!validInput.reasoning, hasConclusion: !!validInput.conclusion, stepCount: validInput.steps?.length ?? 0, } }; } // Backward compatibility method for tests processModel(input) { try { const validatedInput = this.validate(input); const result = this.handle(validatedInput); const response = this.run(input); return { ...response, data: validatedInput // Add the validated input data for test compatibility }; } catch (error) { return { content: [{ type: "text", text: JSON.stringify({ error: error instanceof Error ? error.message : String(error), status: 'failed' }, null, 2) }], isError: true }; } } analyze(modelData) { const quality = { completenessScore: 0, clarityScore: 0, coherenceScore: 0, overallRating: 'N/A' }; let totalScore = 0; let criteriaCount = 0; if (modelData.problem.length > 20) { totalScore += 1; } criteriaCount++; if (modelData.steps && modelData.steps.length > 0) { quality.completenessScore += 0.4; if (modelData.steps.every(s => s.length > 10)) { quality.clarityScore += 0.4; } } if (modelData.reasoning && modelData.reasoning.length > 30) { quality.completenessScore += 0.3; quality.coherenceScore += 0.4; } if (modelData.conclusion && modelData.conclusion.length > 20) { quality.completenessScore += 0.3; quality.coherenceScore += 0.6; } const stepComplexity = modelData.steps ? modelData.steps.length : 0; const textComplexity = (modelData.problem.length + (modelData.reasoning?.length ?? 0) + (modelData.conclusion?.length ?? 0)) / 100; const totalComplexity = stepComplexity + textComplexity; let complexity = 'low'; if (totalComplexity > 10) { complexity = 'high'; } else if (totalComplexity > 5) { complexity = 'medium'; } const textCorpus = [modelData.problem, modelData.reasoning, modelData.conclusion, ...(modelData.steps || [])].join(' '); const keywords = [...new Set(textCorpus.toLowerCase().match(/\b\w{5,15}\b/g) || [])].slice(0, 10); const suggestions = []; if (quality.completenessScore < 0.7) { suggestions.push("Consider adding more detail to the reasoning or conclusion for a more complete analysis."); } if (!modelData.steps || modelData.steps.length < 3) { suggestions.push("Breaking the problem down into more steps could provide deeper insight."); } if (quality.coherenceScore < 0.5) { suggestions.push("Ensure the conclusion logically follows from the reasoning and steps."); } return { quality, complexity, keywords, suggestions }; } formatMentalModelOutput(modelData) { const sections = { 'Model': modelData.modelName, 'Problem': modelData.problem }; if (modelData.steps && modelData.steps.length > 0) { sections['Steps'] = modelData.steps.map(step => `• ${step}`); } if (modelData.reasoning) { sections['Reasoning'] = modelData.reasoning; } if (modelData.conclusion) { sections['Conclusion'] = modelData.conclusion; } return boxed('🧠 Mental Model', sections); } }