Thought Space - MCP Advanced Branch-Thinking Tool
by ssdeanx
- dist
import chalk from 'chalk';
import { SemanticProcessor } from './semanticProcessor.js';
import { BiasDetector } from './biasDetector.js';
import { AnalyticsEngine } from './analytics.js';
export class BranchManager {
constructor() {
this.branches = new Map();
this.insightCounter = 0;
this.thoughtCounter = 0;
this.crossRefCounter = 0;
this.activeBranchId = null;
this.reinforcementLearning = {
learningRate: 0.1,
decayFactor: 0.95,
explorationRate: 0.2
};
this.semanticProcessor = new SemanticProcessor();
this.temporalEvolutionMap = new Map();
this.analyticsEngine = new AnalyticsEngine();
this.biasDetector = new BiasDetector();
}
generateId(prefix) {
const timestamp = Date.now();
const random = Math.floor(Math.random() * 1000);
return `${prefix}-${timestamp}-${random}`;
}
createBranch(branchId, parentBranchId) {
const branch = {
id: branchId,
parentBranchId,
state: 'active',
priority: 1.0,
confidence: 1.0,
thoughts: [],
insights: [],
crossRefs: []
};
this.branches.set(branchId, branch);
// Set as active if it's the first branch
if (!this.activeBranchId) {
this.activeBranchId = branchId;
}
return branch;
}
createInsight(type, content, context, parentInsights) {
return {
id: `insight-${++this.insightCounter}`,
type,
content,
context,
parentInsights,
applicabilityScore: 1.0,
supportingEvidence: {}
};
}
createCrossReference(fromBranch, toBranch, type, reason, strength) {
return {
id: `xref-${++this.crossRefCounter}`,
fromBranch,
toBranch,
type,
reason,
strength,
touchpoints: []
};
}
addThought(input) {
// Use active branch if no branchId provided
const branchId = input.branchId || this.activeBranchId || this.generateId('branch');
let branch = this.branches.get(branchId);
if (!branch) {
branch = this.createBranch(branchId, input.parentBranchId);
}
const thought = {
id: `thought-${++this.thoughtCounter}`,
content: input.content,
branchId: branch.id,
timestamp: new Date(),
metadata: {
type: input.type,
confidence: input.confidence || 1.0,
keyPoints: input.keyPoints || []
}
};
branch.thoughts.push(thought);
// Create insights if key points are provided
if (input.keyPoints) {
const insight = this.createInsight('observation', `Identified key points: ${input.keyPoints.join(', ')}`, [input.type], input.relatedInsights);
branch.insights.push(insight);
}
// Create cross references if specified
if (input.crossRefs) {
input.crossRefs.forEach(ref => {
const crossRef = this.createCrossReference(branch.id, ref.toBranch, ref.type, ref.reason, ref.strength);
branch.crossRefs.push(crossRef);
});
}
this.updateBranchMetrics(branch);
return thought;
}
updateBranchMetrics(branch) {
const avgConfidence = branch.thoughts.reduce((sum, t) => sum + t.metadata.confidence, 0) / branch.thoughts.length;
const insightScore = branch.insights.length * 0.1;
const crossRefScore = branch.crossRefs.reduce((sum, ref) => sum + ref.strength, 0) * 0.1;
branch.priority = avgConfidence + insightScore + crossRefScore;
branch.confidence = avgConfidence;
}
getBranch(branchId) {
return this.branches.get(branchId);
}
getAllBranches() {
return Array.from(this.branches.values());
}
getActiveBranch() {
return this.activeBranchId ? this.branches.get(this.activeBranchId) : undefined;
}
setActiveBranch(branchId) {
if (!this.branches.has(branchId)) {
throw new Error(`Branch ${branchId} not found`);
}
this.activeBranchId = branchId;
}
getBranchHistory(branchId) {
const branch = this.branches.get(branchId);
if (!branch) {
throw new Error(`Branch ${branchId} not found`);
}
const header = chalk.blue(`History for branch: ${branchId} (${branch.state})`);
const timeline = branch.thoughts.map((t, i) => {
const timestamp = t.timestamp.toLocaleTimeString();
const number = chalk.gray(`${i + 1}.`);
const content = t.content;
const type = chalk.yellow(`[${t.metadata.type}]`);
const points = t.metadata.keyPoints.length > 0
? chalk.green(`\n Key Points: ${t.metadata.keyPoints.join(', ')}`)
: '';
return `${number} ${timestamp} ${type}\n ${content}${points}`;
}).join('\n\n');
const insights = branch.insights.map(i => chalk.yellow(`→ ${i.content}`)).join('\n');
return `
┌─────────────────────────────────────────────
│ ${header}
├─────────────────────────────────────────────
${timeline}
${insights ? `
├─────────────────────────────────────────────
│ Insights:
${insights}` : ''}
└─────────────────────────────────────────────`;
}
formatBranchStatus(branch) {
const isActive = branch.id === this.activeBranchId;
const header = `${chalk.blue('Branch:')} ${branch.id} (${branch.state})${isActive ? chalk.green(' [ACTIVE]') : ''}`;
const stats = `Priority: ${branch.priority.toFixed(2)} | Confidence: ${branch.confidence.toFixed(2)}`;
const thoughts = branch.thoughts.map(t => ` ${chalk.green('•')} ${t.content} (${t.metadata.type})`).join('\n');
const insights = branch.insights.map(i => ` ${chalk.yellow('→')} ${i.content}`).join('\n');
const crossRefs = branch.crossRefs.map(r => ` ${chalk.magenta('↔')} ${r.toBranch}: ${r.reason} (${r.strength.toFixed(2)})`).join('\n');
return `
┌─────────────────────────────────────────────
│ ${header}
│ ${stats}
├─────────────────────────────────────────────
│ Thoughts:
${thoughts}
│ Insights:
${insights}
│ Cross References:
${crossRefs}
└─────────────────────────────────────────────`;
}
async visualizeBranch(branchId, config = {}) {
const branch = this.getBranch(branchId);
if (!branch)
throw new Error(`Branch ${branchId} not found`);
const defaultConfig = {
layout: 'force',
style: {
nodeSize: 10,
edgeWidth: 1,
colorScheme: ['#1f77b4', '#ff7f0e', '#2ca02c'],
highlightColor: '#d62728'
},
filters: {
minConfidence: 0.5
},
interactions: {
zoom: true,
drag: true,
highlight: true,
details: true
}
};
const finalConfig = { ...defaultConfig, ...config };
branch.visualizationData = {
layout: finalConfig.layout,
positions: new Map()
};
// Calculate positions based on layout algorithm
switch (finalConfig.layout) {
case 'force':
await this.calculateForceLayout(branch);
break;
case 'hierarchical':
await this.calculateHierarchicalLayout(branch);
break;
case 'radial':
await this.calculateRadialLayout(branch);
break;
case 'temporal':
await this.calculateTemporalLayout(branch);
break;
}
}
async calculateForceLayout(branch) {
// Implement force-directed layout algorithm
// This would use something like d3-force in a real implementation
}
async calculateHierarchicalLayout(branch) {
// Implement hierarchical layout algorithm
}
async calculateRadialLayout(branch) {
// Implement radial layout algorithm
}
async calculateTemporalLayout(branch) {
// Implement temporal layout algorithm
}
async detectContradictions(branchId) {
const branch = this.getBranch(branchId);
if (!branch)
throw new Error(`Branch ${branchId} not found`);
const contradictions = [];
// Implement contradiction detection logic
// This would analyze semantic relationships and logical consistency
return contradictions;
}
async applyReinforcement(branchId, feedback) {
const branch = this.getBranch(branchId);
if (!branch)
throw new Error(`Branch ${branchId} not found`);
if (!branch.reinforcementData) {
branch.reinforcementData = {
learningRate: this.reinforcementLearning.learningRate,
rewardHistory: [],
modelParameters: new Map()
};
}
// Apply reinforcement learning updates
for (const { nodeId, reward } of feedback) {
const node = branch.nodes.find(n => n.id === nodeId);
if (node) {
// Update confidence based on reward
node.confidence = this.updateConfidence(node.confidence, reward, branch.reinforcementData.learningRate);
// Record reward history
branch.reinforcementData.rewardHistory.push({
timestamp: new Date(),
reward
});
}
}
}
updateConfidence(currentConfidence, reward, learningRate) {
const newConfidence = currentConfidence + learningRate * (reward - currentConfidence);
return Math.max(0, Math.min(1, newConfidence));
}
async semanticSearch(query, options = {}) {
const threshold = options.threshold ?? 0.7;
const maxResults = options.maxResults ?? 10;
const queryEmbedding = await this.semanticProcessor.embedText(query);
const results = [];
const branches = options.branchId ?
[this.getBranch(options.branchId)] :
this.getAllBranches();
for (const branch of branches) {
if (!branch)
continue;
for (const node of branch.nodes) {
if (!node.embedding) {
node.embedding = await this.semanticProcessor.embedText(node.label);
}
const similarity = this.semanticProcessor.calculateSimilarity(queryEmbedding, node.embedding);
if (similarity >= threshold) {
results.push({ node: node, similarity });
}
}
}
return results
.sort((a, b) => b.similarity - a.similarity)
.slice(0, maxResults);
}
async findMultiHopPath(startNodeId, endNodeId, maxDepth = 5) {
const paths = [];
const visited = new Set();
const dfs = async (currentId, path, reasoning, depth) => {
if (depth > maxDepth)
return;
if (currentId === endNodeId) {
paths.push({
path,
confidence: reasoning.reduce((acc, step) => acc * step.confidence, 1),
evidence: [],
intermediateSteps: reasoning
});
return;
}
visited.add(currentId);
const currentNode = this.findNodeById(currentId);
if (!currentNode)
return;
for (const link of currentNode.semanticLinks) {
if (!visited.has(link.targetId)) {
const nextNode = this.findNodeById(link.targetId);
if (!nextNode)
continue;
const stepReasoning = {
from: currentId,
to: link.targetId,
reasoning: `Connected via ${link.relationship} relationship`,
confidence: link.similarity
};
await dfs(link.targetId, [...path, link.targetId], [...reasoning, stepReasoning], depth + 1);
}
}
visited.delete(currentId);
};
await dfs(startNodeId, [startNodeId], [], 0);
return paths.sort((a, b) => b.confidence - a.confidence);
}
trackTemporalEvolution(nodeId) {
const node = this.findNodeById(nodeId);
if (!node)
throw new Error(`Node ${nodeId} not found`);
let evolution = this.temporalEvolutionMap.get(nodeId);
if (!evolution) {
evolution = {
nodeId,
timestamps: [],
confidenceHistory: [],
stateTransitions: []
};
this.temporalEvolutionMap.set(nodeId, evolution);
}
// Record current state
evolution.timestamps.push(new Date());
evolution.confidenceHistory.push(node.confidence);
// Check for state transitions
const currentState = node.evolutionState;
const lastTransition = evolution.stateTransitions[evolution.stateTransitions.length - 1];
if (!lastTransition || lastTransition.to !== currentState) {
evolution.stateTransitions.push({
from: lastTransition?.to || 'initial',
to: currentState,
timestamp: new Date(),
reason: this.determineTransitionReason(node)
});
}
// Update temporal score based on evolution history
node.temporalScore = this.calculateTemporalScore(evolution);
}
findNodeById(nodeId) {
for (const branch of this.getAllBranches()) {
const enhancedBranch = branch;
const node = enhancedBranch.nodes.find(n => n.id === nodeId);
if (node)
return node;
}
return undefined;
}
determineTransitionReason(node) {
// Implement logic to determine why a state transition occurred
// This could be based on confidence changes, contradictions, etc.
return "State transition based on updated evidence and confidence";
}
calculateTemporalScore(evolution) {
const recentConfidence = evolution.confidenceHistory.slice(-5);
const trend = recentConfidence.reduce((acc, conf, i) => {
return acc + conf * Math.exp(-0.2 * (recentConfidence.length - i - 1));
}, 0) / recentConfidence.length;
const stateStability = 1 - (evolution.stateTransitions.length / evolution.timestamps.length);
return (trend * 0.7 + stateStability * 0.3);
}
async analyzeBranch(branchId) {
const branch = this.getBranch(branchId);
if (!branch) {
throw new Error(`Branch ${branchId} not found`);
}
return this.analyticsEngine.generateBranchAnalytics(branch);
}
async detectBranchBias(branchId) {
const branch = this.getBranch(branchId);
if (!branch)
throw new Error(`Branch ${branchId} not found`);
return [...(await this.biasDetector.detectBias(branch.nodes))];
}
}