@emmahyde/thought-patterns
Version:
MCP server combining systematic thinking, mental models, debugging approaches, and stochastic algorithms for comprehensive cognitive pattern support
125 lines (124 loc) • 5.41 kB
JavaScript
import { BaseToolServer } from '../base/BaseToolServer.js';
import { ThoughtSchema } from '../schemas/index.js';
import { boxed } from '../utils/index.js';
/**
* Sequential Thinking Server using clear-thought tools approach
* Extends BaseToolServer for standardized validation and error handling
*/
export class SequentialThinkingServer extends BaseToolServer {
constructor() {
super(ThoughtSchema);
}
handle(validInput) {
return this.process(validInput);
}
/**
* Standardized process method for sequential thinking
* @param validInput - Validated thought data
* @returns Processed thought result
*/
process(validInput) {
// Format output using boxed utility
const formattedOutput = this.formatThoughtOutput(validInput);
// Log formatted output to console (suppress during tests)
if (process.env.NODE_ENV !== 'test' && process.env.JEST_WORKER_ID === undefined) {
console.error(formattedOutput);
}
return {
thoughtNumber: validInput.thoughtNumber,
totalThoughts: validInput.totalThoughts,
nextThoughtNeeded: validInput.nextThoughtNeeded,
thought: validInput.thought,
status: 'success',
isRevision: validInput.isRevision || false,
hasCurrentStep: !!validInput.currentStep,
branchId: validInput.branchId,
stage: this.determineStage(validInput.thoughtNumber, validInput.totalThoughts),
timestamp: new Date().toISOString(),
framework: 'clear-thought-tools'
};
}
// Backward compatibility method for existing tests
processThought(input) {
return this.run(input);
}
formatThoughtOutput(data) {
const sections = {
'Thought': `${data.thoughtNumber}/${data.totalThoughts}`,
'Content': data.thought
};
if (data.isRevision && data.revisesThought) {
sections['Type'] = `REVISION (revising thought ${data.revisesThought})`;
}
else if (data.branchFromThought && data.branchId) {
sections['Type'] = `BRANCH (from thought ${data.branchFromThought}, ID: ${data.branchId})`;
}
else {
sections['Type'] = 'SEQUENTIAL';
}
// Current step information
if (data.currentStep) {
const step = data.currentStep;
sections['Current Step'] = [
`Description: ${step.stepDescription}`,
`Expected Outcome: ${step.expectedOutcome}`,
...(step.estimatedDuration ? [`Duration: ${step.estimatedDuration}`] : []),
...(step.complexityLevel ? [`Complexity: ${step.complexityLevel.toUpperCase()}`] : [])
];
if (step.recommendedTools.length > 0) {
sections['Recommended Tools'] = step.recommendedTools.map(tool => `• ${tool.toolName} (${(tool.confidence * 100).toFixed(0)}%): ${tool.rationale}`);
}
if (step.nextStepConditions.length > 0) {
sections['Next Step Conditions'] = step.nextStepConditions.map(condition => `• ${condition}`);
}
}
// Previous steps
if (data.previousSteps && data.previousSteps.length > 0) {
sections['Previous Steps'] = data.previousSteps.map((step, index) => `${index + 1}. ${step.stepDescription}`);
}
// Remaining steps
if (data.remainingSteps && data.remainingSteps.length > 0) {
sections['Remaining Steps'] = data.remainingSteps.map(step => `• ${step}`);
}
// Tool usage history
if (data.toolUsageHistory && data.toolUsageHistory.length > 0) {
sections['Tool Usage History'] = data.toolUsageHistory.map(usage => {
const effectiveness = usage.effectivenessScore ? ` (${(usage.effectivenessScore * 100).toFixed(0)}%)` : '';
return `• ${usage.toolName} at ${usage.usedAt}${effectiveness}`;
});
}
// Progress information
const progress = Math.round((data.thoughtNumber / data.totalThoughts) * 100);
sections['Progress'] = `${progress}% (${data.thoughtNumber}/${data.totalThoughts})`;
if (data.needsMoreThoughts) {
sections['Status'] = 'MORE THOUGHTS NEEDED';
}
else if (data.nextThoughtNeeded) {
sections['Status'] = 'NEXT THOUGHT NEEDED';
}
else {
sections['Status'] = 'SEQUENCE COMPLETE';
}
return boxed('💭 Sequential Thinking', sections);
}
determineStage(thoughtNumber, totalThoughts) {
// Handle edge cases first
if (totalThoughts === 1)
return 'final'; // Single thought is always final
if (thoughtNumber === 1 && totalThoughts > 1)
return 'initial';
if (thoughtNumber === totalThoughts)
return 'final';
// For sequences with 2 thoughts, first is initial, second is final
if (totalThoughts === 2) {
return thoughtNumber === 1 ? 'initial' : 'final';
}
// For longer sequences, use proportional logic
const progress = thoughtNumber / totalThoughts;
if (progress <= 0.33)
return 'initial';
if (progress >= 0.67)
return 'final';
return 'middle';
}
}