UNPKG

@waldzellai/clear-thought-onepointfive

Version:

Clear Thought MCP server with modular architecture - 38 reasoning operations for systematic thinking

1,200 lines (1,191 loc) 107 kB
import { z } from "zod"; import { EphemeralNotebookStore } from "../notebook/EphemeralNotebook.js"; import { getPresetForPattern } from "../notebook/presets.js"; import { executePython } from "../utils/execution.js"; import { enhanceResponseWithNotebook } from "./notebookEnhancement.js"; // Initialize notebook store const notebookStore = new EphemeralNotebookStore(); /** * Helper function to generate dashboard HTML content */ function generateDashboardHTML(options) { const { title, visualizationType, data, panels, layout, interactive } = options; // Generate HTML with embedded Chart.js or D3.js visualization const chartScript = visualizationType === "chart" ? ` <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script> const ctx = document.getElementById('mainChart').getContext('2d'); const chart = new Chart(ctx, { type: '${data.chartType || "bar"}', data: ${JSON.stringify(data.chartData || { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'], datasets: [{ label: 'Dataset', data: [12, 19, 3, 5, 2], backgroundColor: 'rgba(75, 192, 192, 0.2)', borderColor: 'rgba(75, 192, 192, 1)', borderWidth: 1 }] })}, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true }, tooltip: { enabled: ${interactive} } } } }); </script> ` : ""; const panelsHTML = panels.map((panel, index) => ` <div class="panel" style=" padding: 15px; margin: 10px; border: 1px solid #ddd; border-radius: 8px; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); "> <h3>${panel.title || `Panel ${index + 1}`}</h3> <div class="panel-content"> ${panel.content || `<p>Panel content for ${panel.type || 'metric'}</p>`} ${panel.value ? `<div class="metric-value" style="font-size: 2em; font-weight: bold; color: #2196F3;">${panel.value}</div>` : ''} </div> </div> `).join(''); return ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>${title}</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; } .dashboard { max-width: 1200px; margin: 0 auto; } .header { background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .panels-container { display: ${layout === 'grid' ? 'grid' : 'flex'}; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; flex-wrap: ${layout === 'flex' ? 'wrap' : 'nowrap'}; } .chart-container { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); height: 400px; margin-bottom: 20px; } canvas { width: 100% !important; height: 100% !important; } </style> </head> <body> <div class="dashboard"> <div class="header"> <h1>${title}</h1> <p>Interactive Dashboard - ${new Date().toLocaleString()}</p> </div> ${visualizationType === 'chart' ? ` <div class="chart-container"> <canvas id="mainChart"></canvas> </div> ` : ''} <div class="panels-container"> ${panelsHTML} </div> </div> ${chartScript} ${interactive ? ` <script> // Enable interactive features window.parent.postMessage({ type: 'ui-lifecycle-iframe-ready', payload: { ready: true } }, '*'); // Handle clicks on panels document.querySelectorAll('.panel').forEach((panel, index) => { panel.style.cursor = 'pointer'; panel.addEventListener('click', () => { window.parent.postMessage({ type: 'notify', payload: { message: 'Panel ' + (index + 1) + ' clicked' } }, '*'); }); }); </script> ` : ''} </body> </html> `; } /** * Helper function to generate remote DOM script for dynamic content */ function generateRemoteDomScript(options) { const { visualizationType, data, panels, interactive } = options; return ` // Create dashboard container const container = document.createElement('ui-container'); container.style.padding = '20px'; // Add title const title = document.createElement('ui-text'); title.textContent = 'Dynamic Dashboard'; title.style.fontSize = '24px'; title.style.fontWeight = 'bold'; title.style.marginBottom = '20px'; container.appendChild(title); // Add panels ${panels.map((panel, index) => ` const panel${index} = document.createElement('ui-panel'); panel${index}.style.padding = '15px'; panel${index}.style.margin = '10px'; panel${index}.style.border = '1px solid #ddd'; panel${index}.style.borderRadius = '8px'; const panelTitle${index} = document.createElement('ui-text'); panelTitle${index}.textContent = '${panel.title || `Panel ${index + 1}`}'; panelTitle${index}.style.fontWeight = 'bold'; panel${index}.appendChild(panelTitle${index}); ${panel.value ? ` const panelValue${index} = document.createElement('ui-text'); panelValue${index}.textContent = '${panel.value}'; panelValue${index}.style.fontSize = '2em'; panelValue${index}.style.color = '#2196F3'; panel${index}.appendChild(panelValue${index}); ` : ''} ${interactive ? ` panel${index}.style.cursor = 'pointer'; panel${index}.onclick = () => { window.parent.postMessage({ type: 'tool', payload: { toolName: 'handlePanelClick', params: { panelId: ${index} } } }, '*'); }; ` : ''} container.appendChild(panel${index}); `).join('\n')} // Append to root root.appendChild(container); // Send ready signal window.parent.postMessage({ type: 'ui-lifecycle-iframe-ready', payload: { ready: true } }, '*'); `; } /** * Registers the unified Clear Thought tool with the MCP server * * This single tool provides access to all reasoning operations through * an operation parameter, following the Toolhost pattern. * * @param server - The MCP server instance * @param sessionState - The session state manager */ export const ClearThoughtParamsSchema = z.object({ operation: z .enum([ // Core thinking operations "sequential_thinking", "mental_model", "debugging_approach", "creative_thinking", "visual_reasoning", "metacognitive_monitoring", "scientific_method", // Collaborative operations "collaborative_reasoning", "decision_framework", "socratic_method", "structured_argumentation", // Systems and session operations "systems_thinking", "session_info", "session_export", "session_import", // Deep reasoning operations "pdr_reasoning", // New modules "research", "analogical_reasoning", "causal_analysis", "statistical_reasoning", "simulation", "optimization", "ethical_analysis", "visual_dashboard", "custom_framework", "code_execution", // Reasoning pattern operations "tree_of_thought", "beam_search", "mcts", "graph_of_thought", "orchestration_suggest", // Metagame operations "ooda_loop", "ulysses_protocol", // Notebook operations "notebook_create", "notebook_add_cell", "notebook_run_cell", "notebook_export", ]) .describe("What type of reasoning operation to perform"), // Common parameters prompt: z.string().describe("The problem, question, or challenge to work on"), context: z .string() .optional() .describe("Additional context or background information"), sessionId: z .string() .optional() .describe("Session identifier for continuity"), // Operation-specific parameters (will be validated based on operation) parameters: z .record(z.string(), z.unknown()) .optional() .describe("Operation-specific parameters"), // Advanced options advanced: z .object({ autoProgress: z .boolean() .optional() .describe("Automatically progress through stages when applicable"), saveToSession: z .boolean() .default(true) .describe("Save results to session state"), generateNextSteps: z .boolean() .default(true) .describe("Generate recommended next steps"), }) .optional() .describe("Advanced reasoning options"), }); export async function handleClearThoughtTool(sessionState, args) { const startTime = Date.now(); try { // Special handling for code execution to allow real run if (args.operation === "code_execution") { const params = (args.parameters || {}); const lang = params.language || "python"; const code = String(params.code || ""); const cfg = sessionState.getConfig(); if (lang !== "python" || !cfg.allowCodeExecution) { const preview = await executeClearThoughtOperation(sessionState, args.operation, { prompt: args.prompt, parameters: args.parameters }); return { content: [{ type: "text", text: JSON.stringify(preview, null, 2) }], }; } const result = await executePython(code, cfg.pythonCommand, cfg.executionTimeoutMs); const executionResult = { toolOperation: "code_execution", ...result }; return { content: [ { type: "text", text: JSON.stringify(executionResult, null, 2), }, ], }; } // Auto-seed most operations with a brief sequential_thinking step const seedExclusions = new Set([ "sequential_thinking", "code_execution", "session_info", "session_export", "session_import", ]); const shouldSeed = !seedExclusions.has(args.operation); // Handle async operations if (args.operation === "notebook_run_cell") { const params = (args.parameters || {}); try { const execution = await notebookStore.executeCell(params.notebookId || "", params.cellId || "", params.timeoutMs || 5000); const notebookResult = { toolOperation: "notebook_run_cell", notebookId: params.notebookId, cellId: params.cellId, execution: { id: execution.id, status: execution.status, outputs: execution.outputs, error: execution.error, duration: execution.completedAt ? execution.completedAt - execution.startedAt : undefined, }, }; return { content: [ { type: "text", text: JSON.stringify(notebookResult, null, 2), }, ], }; } catch (error) { const errorResult = { toolOperation: "notebook_run_cell", notebookId: params.notebookId, cellId: params.cellId, error: error.message, success: false, }; return { content: [ { type: "text", text: JSON.stringify(errorResult, null, 2), }, ], }; } } // Execute the main operation const result = await executeClearThoughtOperation(sessionState, args.operation, { prompt: args.prompt, parameters: args.parameters }); const enriched = shouldSeed ? { ...result, initialThought: await executeClearThoughtOperation(sessionState, "sequential_thinking", { prompt: `Plan approach for: ${args.prompt}`, parameters: { thoughtNumber: 1, totalThoughts: 3, nextThoughtNeeded: true, needsMoreThoughts: true, pattern: "chain", }, }), } : result; // Enhance response with notebook resources if applicable const baseResponse = { content: [{ type: "text", text: JSON.stringify(enriched, null, 2) }], }; const enhancedResponse = enhanceResponseWithNotebook(baseResponse, args.operation, args.prompt); return enhancedResponse; } catch (error) { const errorResponse = { toolOperation: args.operation, error: error.message, success: false }; return { content: [ { type: "text", text: JSON.stringify(errorResponse, null, 2), }, ], isError: true, }; } } // Backwards-compatible registration helper (kept for compatibility; unused by low-level Server) export function registerTools(server, sessionState) { server.tool("clear_thought", "Unified Clear Thought reasoning tool - provides all reasoning operations through a single interface", ClearThoughtParamsSchema.shape, async (args) => handleClearThoughtTool(sessionState, args)); } /** * Unified Clear Thought reasoning operations * * This module provides all reasoning operations through a single interface, * following the websetsManager pattern without external dependencies. * * @param sessionState - The session state manager * @param operation - The operation to perform * @param args - Operation arguments */ export async function executeClearThoughtOperation(sessionState, operation, args) { const { prompt, parameters = {} } = args; // Optional reasoning pattern selection for sequential_thinking const specifiedPattern = parameters.pattern; const patternParams = parameters.patternParams || {}; const selectReasoningPattern = () => { if (specifiedPattern && specifiedPattern !== "auto") return specifiedPattern; // Heuristic selection from prompt/params const ptext = `${prompt}`.toLowerCase(); if ("depth" in patternParams || "breadth" in patternParams || ptext.includes("branch") || ptext.includes("options")) { return "tree"; } if ("beamWidth" in patternParams || ptext.includes("candidates") || ptext.includes("top-k")) { return "beam"; } if ("simulations" in patternParams || ptext.includes("uncertain") || ptext.includes("probability") || ptext.includes("stochastic")) { return "mcts"; } if ("nodes" in patternParams || "edges" in patternParams || ptext.includes("dependencies") || ptext.includes("graph")) { return "graph"; } return "chain"; }; // Type guard to ensure parameters are properly typed const getParam = (key, defaultValue) => { return parameters[key] ?? defaultValue; }; // Unified handler for all operations switch (operation) { case "sequential_thinking": { // Choose reasoning pattern (default 'chain') and optionally dispatch const chosenPattern = selectReasoningPattern(); const thoughtData = { thought: prompt, thoughtNumber: parameters.thoughtNumber || 1, totalThoughts: parameters.totalThoughts || 1, nextThoughtNeeded: parameters.nextThoughtNeeded || false, isRevision: parameters.isRevision, revisesThought: parameters.revisesThought, branchFromThought: parameters.branchFromThought, branchId: parameters.branchId, needsMoreThoughts: parameters.needsMoreThoughts, }; const added = sessionState.addThought(thoughtData); const allThoughts = sessionState.getThoughts(); const recentThoughts = allThoughts.slice(-3); // If a non-chain pattern is selected, optionally execute the corresponding pattern operation let patternResult; if (chosenPattern !== "chain" && !parameters.__disablePatternDispatch) { const opMap = { tree: "tree_of_thought", beam: "beam_search", mcts: "mcts", graph: "graph_of_thought", }; const mappedOp = opMap[chosenPattern]; if (mappedOp) { patternResult = await executeClearThoughtOperation(sessionState, mappedOp, { prompt, parameters: patternParams }); } } return { toolOperation: "sequential_thinking", selectedPattern: chosenPattern, patternResult, ...thoughtData, status: added ? "success" : "limit_reached", sessionContext: { sessionId: sessionState.sessionId, totalThoughts: allThoughts.length, remainingThoughts: sessionState.getRemainingThoughts(), recentThoughts: recentThoughts.map((t) => ({ thoughtNumber: t.thoughtNumber, isRevision: t.isRevision, })), }, }; } case "mental_model": { const modelData = { modelName: parameters.model || "first_principles", problem: prompt, steps: parameters.steps || [], reasoning: parameters.reasoning || "", conclusion: parameters.conclusion || "", }; sessionState.addMentalModel(modelData); const allModels = sessionState.getMentalModels(); return { toolOperation: "mental_model", ...modelData, sessionContext: { sessionId: sessionState.sessionId, totalModels: allModels.length, recentModels: allModels .slice(-3) .map((m) => ({ modelName: m.modelName, problem: m.problem })), }, }; } case "debugging_approach": { const debugData = { approachName: parameters.approach || "binary_search", issue: prompt, steps: parameters.steps || [], findings: parameters.findings || "", resolution: parameters.resolution || "", }; sessionState.addDebuggingSession(debugData); const allSessions = sessionState.getDebuggingSessions(); return { toolOperation: "debugging_approach", ...debugData, sessionContext: { sessionId: sessionState.sessionId, totalSessions: allSessions.length, recentSessions: allSessions .slice(-3) .map((s) => ({ approachName: s.approachName, issue: s.issue })), }, }; } case "creative_thinking": { /** * Creative Thinking Operation * * Generates idea seeds and connections using simple combinatorial techniques. * * Expected in prompt: Creative challenge or problem to brainstorm * * Expected in parameters (model should provide these or they'll be generated): * - techniques?: string[] - Creative techniques to apply (default: ["brainstorming", "SCAMPER"]) * - numIdeas?: number - Number of ideas to generate (default: 8) * - ideas?: string[] - Pre-existing ideas to build upon * * The model should either provide structured ideas or the system will generate them using combinatorial techniques. */ // Use provided parameters or generate ideas let ideas = parameters.ideas || []; const techniques = parameters.techniques || ["brainstorming", "SCAMPER"]; const numIdeas = getParam("numIdeas", 8); // Generate ideas if none provided if (ideas.length === 0 && prompt) { // Extract key tokens from prompt const tokens = prompt.toLowerCase() .replace(/[^a-z\s]/g, '') .split(/\s+/) .filter(t => t.length > 2); // SCAMPER verbs for idea generation const scamperVerbs = [ "substitute", "combine", "adapt", "modify", "put to other use", "eliminate", "reverse" ]; // Generate ideas by combining tokens with techniques for (let i = 0; i < numIdeas && tokens.length > 0; i++) { const token = tokens[i % tokens.length]; const verb = scamperVerbs[i % scamperVerbs.length]; const otherToken = tokens[(i + 1) % tokens.length]; ideas.push(`${verb} ${token} with ${otherToken}`); } } // Generate connections between concepts let connections = parameters.connections || []; if (connections.length === 0 && ideas.length > 1) { // Create connections between ideas for (let i = 0; i < Math.min(ideas.length - 1, 3); i++) { connections.push(`${ideas[i]} could lead to ${ideas[i + 1]}`); } } // Generate insights (top-ranked ideas by novelty and coverage) let insights = parameters.insights || []; if (insights.length === 0 && ideas.length > 0) { // Simple ranking: pick ideas with rare tokens (novelty) and prompt overlap (coverage) const promptTokens = new Set(prompt.toLowerCase().split(/\s+/)); const rankedIdeas = ideas .map(idea => { const ideaTokens = idea.toLowerCase().split(/\s+/); const coverage = ideaTokens.filter(t => promptTokens.has(t)).length / ideaTokens.length; const novelty = 1 - coverage; // Simple novelty heuristic const score = (coverage + novelty) / 2; return { idea, score }; }) .sort((a, b) => b.score - a.score) .slice(0, 3) .map(item => item.idea); insights = rankedIdeas; } const creativeData = { prompt: prompt, ideas, techniques, connections, insights, sessionId: `creative-${Date.now()}`, iteration: getParam("iteration", 1), nextIdeaNeeded: getParam("nextIdeaNeeded", false), }; sessionState.addCreativeSession(creativeData); const allSessions = sessionState.getCreativeSessions(); return { toolOperation: "creative_thinking", ...creativeData, sessionContext: { sessionId: sessionState.sessionId, totalSessions: allSessions.length, recentSessions: allSessions .slice(-3) .map((s) => ({ prompt: s.prompt, techniques: s.techniques })), }, }; } case "visual_reasoning": { const visualData = { operation: "create", diagramId: getParam("diagramId", `diagram-${Date.now()}`), diagramType: getParam("diagramType", "flowchart"), iteration: getParam("iteration", 1), nextOperationNeeded: getParam("nextOperationNeeded", false), }; sessionState.addVisualOperation(visualData); const allOperations = sessionState.getVisualOperations(); return { toolOperation: "visual_reasoning", ...visualData, sessionContext: { sessionId: sessionState.sessionId, totalOperations: allOperations.length, recentOperations: allOperations .slice(-3) .map((v) => ({ diagramType: v.diagramType, operation: v.operation, })), }, }; } case "metacognitive_monitoring": { /** * Metacognitive Monitoring Operation * * Records stage, uncertainty areas, and recommended approach; suggests assessments. * * Expected in prompt: Task or problem being monitored * * Expected in parameters: * - stage?: 'planning' | 'monitoring' | 'evaluating' | 'reflecting' * - uncertaintyAreas?: string[] - Areas of uncertainty * - overallConfidence?: number - Confidence level (0-1) * - recommendedApproach?: string - Suggested approach */ const stage = getParam("stage", "monitoring"); const uncertaintyAreas = getParam("uncertaintyAreas", []); const overallConfidence = getParam("overallConfidence", 0.5); const recommendedApproach = getParam("recommendedApproach", ""); // Suggest assessments based on stage let suggestedAssessments = []; if (stage === "monitoring") { suggestedAssessments = ["knowledge", "progress", "overall"]; } else if (stage === "evaluating") { suggestedAssessments = ["effectiveness", "efficiency", "completeness"]; } else if (stage === "reflecting") { suggestedAssessments = ["lessons-learned", "improvements", "next-steps"]; } const metaData = { task: prompt, stage, overallConfidence, uncertaintyAreas, recommendedApproach, suggestedAssessments, monitoringId: `meta-${Date.now()}`, iteration: getParam("iteration", 1), nextAssessmentNeeded: suggestedAssessments.length > 0, }; sessionState.addMetacognitive(metaData); sessionState.updateKPI('overall_confidence', overallConfidence); const allSessions = sessionState.getMetacognitiveSessions(); return { toolOperation: "metacognitive_monitoring", ...metaData, sessionContext: { sessionId: sessionState.sessionId, totalSessions: allSessions.length, recentSessions: allSessions .slice(-3) .map((m) => ({ task: m.task, stage: m.stage })), }, }; } case "scientific_method": { const scientificData = { stage: getParam("stage", "hypothesis"), inquiryId: `sci-${Date.now()}`, iteration: getParam("iteration", 1), nextStageNeeded: getParam("nextStageNeeded", false), }; sessionState.addScientificInquiry(scientificData); const allInquiries = sessionState.getScientificInquiries(); return { toolOperation: "scientific_method", ...scientificData, sessionContext: { sessionId: sessionState.sessionId, totalInquiries: allInquiries.length, recentInquiries: allInquiries .slice(-3) .map((s) => ({ stage: s.stage })), }, }; } case "collaborative_reasoning": { /** * Collaborative Reasoning Operation * * Maintains personas and contributions; suggests next contribution types. * * Expected in prompt: Topic or problem for collaborative analysis * * Expected in parameters: * - personas?: Array<{id: string, name: string, expertise: string[]}> * - contributions?: Array<{personaId: string, content: string, type: string}> * - stage?: 'problem-definition' | 'exploration' | 'synthesis' | 'conclusion' */ const personas = parameters.personas || []; let contributions = parameters.contributions || []; const stage = getParam("stage", "problem-definition"); // Append a synthetic contribution from prompt if none provided if (contributions.length === 0 && prompt) { contributions.push({ personaId: "system", content: prompt, type: "observation", confidence: 0.8 }); } // Suggest next contribution types based on stage let suggestedContributionTypes = []; switch (stage) { case "problem-definition": suggestedContributionTypes = ["question", "concern", "observation"]; break; case "exploration": suggestedContributionTypes = ["insight", "suggestion", "challenge"]; break; case "synthesis": suggestedContributionTypes = ["synthesis", "insight", "question"]; break; case "conclusion": suggestedContributionTypes = ["synthesis", "concern", "observation"]; break; } const collaborativeData = { topic: prompt, personas, contributions, stage, suggestedContributionTypes, nextContributionNeeded: contributions.length < 3, sessionId: `collab-${Date.now()}`, }; return { toolOperation: "collaborative_reasoning", ...collaborativeData, sessionContext: { sessionId: sessionState.sessionId, stats: sessionState.getStats(), }, }; } case "decision_framework": { /** * Decision Framework Operation * * Accepts options/criteria and computes expected-utility or multi-criteria scores. * * Expected in prompt: Decision to be made * * Expected in parameters: * - options: Array<{id: string, name: string, attributes?: Record<string, any>}> * - criteria: Array<{name: string, weight: number, type: 'maximize'|'minimize'}> * - possibleOutcomes?: Array<{option: string, probability: number, value: number}> * - analysisType: 'expected-utility' | 'multi-criteria' */ const options = parameters.options || []; const criteria = parameters.criteria || []; const possibleOutcomes = parameters.possibleOutcomes || []; const analysisType = getParam("analysisType", "multi-criteria"); let result = {}; if (analysisType === "expected-utility" && possibleOutcomes.length > 0) { // Calculate expected values for each option const expectedValues = {}; options.forEach(opt => { const outcomes = possibleOutcomes.filter(o => o.option === opt.id || o.option === opt.name); expectedValues[opt.id || opt.name] = outcomes.reduce((sum, o) => sum + (o.probability * o.value), 0); }); result.expectedValues = expectedValues; const bestOption = Object.entries(expectedValues).reduce((best, [key, val]) => val > best.value ? { id: key, value: val } : best, { id: "", value: -Infinity }); result.recommendation = bestOption.id; } else if (analysisType === "multi-criteria" && criteria.length > 0) { // Multi-criteria scoring const scores = {}; const totalWeight = criteria.reduce((sum, c) => sum + (c.weight || 1), 0); options.forEach(opt => { let score = 0; criteria.forEach(criterion => { const value = opt.attributes?.[criterion.name] || 0; const normalizedWeight = (criterion.weight || 1) / totalWeight; score += value * normalizedWeight; }); scores[opt.id || opt.name] = score; }); result.multiCriteriaScores = scores; const bestOption = Object.entries(scores).reduce((best, [key, val]) => val > best.value ? { id: key, value: val } : best, { id: "", value: -Infinity }); result.recommendation = bestOption.id; } const decisionData = { decisionStatement: prompt, options, criteria, possibleOutcomes, analysisType, ...result, suggestedNextStage: result.recommendation ? "implementation" : "gather-more-data", decisionId: `decision-${Date.now()}`, }; return { toolOperation: "decision_framework", ...decisionData, sessionContext: { sessionId: sessionState.sessionId, stats: sessionState.getStats(), }, }; } case "socratic_method": { /** * Socratic Method Operation * * Builds claims/premises/conclusion structures through questioning. * * Expected in prompt: Initial question or claim to examine * * Expected in parameters: * - claim?: string - The claim being examined * - premises?: string[] - Supporting premises * - stage?: 'clarification' | 'assumptions' | 'reasons' | 'viewpoints' | 'consequences' */ const claim = getParam("claim", ""); let premises = parameters.premises || []; const stage = getParam("stage", "clarification"); // Extract premises from prompt if not provided if (premises.length === 0 && prompt) { // Look for numbered or bulleted reasons const lines = prompt.split(/\n/); lines.forEach(line => { if (/^[\d\-\*•]/.test(line.trim())) { premises.push(line.replace(/^[\d\-\*•\.\)]+\s*/, '').trim()); } }); } // Calculate confidence based on premise strength const strengthKeywords = ['clearly', 'obviously', 'certainly', 'definitely']; const weaknessKeywords = ['maybe', 'perhaps', 'possibly', 'might']; let confidence = 0.5; const allText = `${claim} ${premises.join(' ')}`.toLowerCase(); strengthKeywords.forEach(word => { if (allText.includes(word)) confidence += 0.1; }); weaknessKeywords.forEach(word => { if (allText.includes(word)) confidence -= 0.1; }); confidence = Math.max(0, Math.min(1, confidence)); const socraticData = { question: prompt, claim, premises, conclusion: parameters.conclusion || "", argumentType: parameters.argumentType || "deductive", confidence, stage, nextArgumentNeeded: premises.length < 2, sessionId: `socratic-${Date.now()}`, }; return { toolOperation: "socratic_method", ...socraticData, sessionContext: { sessionId: sessionState.sessionId, stats: sessionState.getStats(), }, }; } case "structured_argumentation": { const argumentData = { claim: prompt, premises: parameters.premises || [], conclusion: parameters.conclusion || "", argumentType: parameters.argumentType || "deductive", confidence: parameters.confidence || 0.5, respondsTo: parameters.respondsTo, supports: parameters.supports || [], contradicts: parameters.contradicts || [], strengths: parameters.strengths || [], weaknesses: parameters.weaknesses || [], relevance: parameters.relevance || 0.5, sessionId: `arg-${Date.now()}`, iteration: parameters.iteration || 1, nextArgumentNeeded: parameters.nextArgumentNeeded || false, }; return { toolOperation: "structured_argumentation", ...argumentData, sessionContext: { sessionId: sessionState.sessionId, stats: sessionState.getStats(), }, }; } case "systems_thinking": { /** * Systems Thinking Operation * * Analyzes complex systems by identifying components, relationships, and feedback loops. * * Expected in prompt: A description of the system to analyze * * Expected in parameters (model should provide these based on analysis): * - components: string[] - Key elements/entities in the system * - relationships: Array<{from: string, to: string, type: string, strength?: number}> - How components interact * - feedbackLoops: Array<{components: string[], type: 'positive'|'negative', description: string}> - Reinforcing or balancing loops * - emergentProperties: string[] - Properties that arise from system interactions * - leveragePoints: string[] - High-impact intervention opportunities * * The model should analyze the system described in the prompt and structure it into these components. */ // Use provided parameters or default to empty arrays const components = parameters.components || []; const relationships = parameters.relationships || []; const feedbackLoops = parameters.feedbackLoops || []; const emergentProperties = parameters.emergentProperties || []; const leveragePoints = parameters.leveragePoints || []; // Validate and detect feedback loops from relationships if not provided if (feedbackLoops.length === 0 && relationships.length > 0) { const graph = new Map(); relationships.forEach((rel) => { if (!graph.has(rel.from)) graph.set(rel.from, new Set()); graph.get(rel.from).add(rel.to); }); // Simple cycle detection (depth 2-3) for (const [start, targets] of graph.entries()) { for (const mid of targets) { if (graph.has(mid)) { for (const end of graph.get(mid)) { if (end === start) { // Found 2-cycle feedbackLoops.push({ components: [start, mid], type: 'negative', description: `${start} -> ${mid} -> ${start}` }); } else if (graph.has(end) && graph.get(end).has(start)) { // Found 3-cycle feedbackLoops.push({ components: [start, mid, end], type: 'positive', description: `${start} -> ${mid} -> ${end} -> ${start}` }); } } } } } } const systemsData = { system: prompt, components, relationships, feedbackLoops, emergentProperties, leveragePoints, sessionId: `systems-${Date.now()}`, iteration: parameters.iteration || 1, nextAnalysisNeeded: parameters.nextAnalysisNeeded || false, }; // Update KPI for systems components if (components.length > 0) { sessionState.updateKPI('systems_components_count', components.length); } return { toolOperation: "systems_thinking", ...systemsData, sessionContext: { sessionId: sessionState.sessionId, stats: sessionState.getStats(), }, }; } case "session_info": { return { toolOperation: "session_info", sessionId: sessionState.sessionId, stats: sessionState.getStats(), }; } case "session_export": { return { toolOperation: "session_export", sessionData: sessionState.export(), }; } case "session_import": { return { toolOperation: "session_import", result: "Session import completed", }; } // -------------------- New modules -------------------- case "pdr_reasoning": { // PDR uses sequential thinking with progressive refinement pattern return await executeClearThoughtOperation(sessionState, "sequential_thinking", { prompt, parameters: { ...parameters, pattern: "chain", patternParams: { depth: 3, breadth: 2, }, }, }); } case "research": { /** * Research Operation * * Structures research intent and placeholders for downstream web tooling (no external calls here). * * Expected in prompt: Research question or topic to investigate * * Expected in parameters (model should provide these): * - subqueries?: string[] - Specific sub-questions to research * - findings?: ResearchFinding[] - Any pre-existing findings * - citations?: ResearchSource[] - Any pre-existing sources * * The model should break down the research prompt into specific, searchable questions. */ const subqueries = parameters.subqueries || []; let findings = parameters.findings || []; let citations = parameters.citations || []; // If no structured input, create placeholder findings from prompt if (findings.length === 0 && prompt) { // Split prompt into claims and questions const sentences = prompt.split(/[.!?]+/).filter(s => s.trim().length > 0); for (const sentence of sentences.slice(0, 3)) { // Limit to first 3 sentences const trimmed = sentence.trim(); if (trimmed) { // Create placeholder finding findings.push({ claim: `Research needed: ${trimmed}`, evidence: "[Evidence to be gathered]", confidence: 0.0, // No evidence yet sources: [] // No sources yet }); } } } // Generate sub-queries if none provided let derivedSubqueries = subqueries; if (derivedSubqueries.length === 0 && prompt) { // Simple heuristic: look for question words and create variants const questionStarters = ['What', 'How', 'Why', 'When', 'Where', 'Who']; const keywords = prompt.split(/\s+/).filter(w => w.length > 3).slice(0, 3); for (const starter of questionStarters.slice(0, 3)) { for (const keyword of keywords.slice(0, 2)) { derivedSubqueries.push(`${starter} ${keyword.toLowerCase()}?`); } } derivedSubqueries = derivedSubqueries.slice(0, 5); // Limit to 5 subqueries } const result = { query: prompt, findings, citations, }; return { toolOperation: "research", ...result, subqueries: derivedSubqueries, note: "This operation structures research intent. Use external tools for actual web search and data gathering." }; } case "analogical_reasoning": { /** * Analogical Reasoning Operation * * Maps source→target concept roles using pattern templates. * * Expected in prompt: Description of analogy or domains to compare * * Expected in parameters (model should provide these): * - sourceDomain: string - The familiar domain to map from * - targetDomain: string - The unfamiliar domain to map to * - mappings?: AnalogyMapping[] - Explicit concept mappings * - inferredInsights?: string[] - Insights derived from the analogy * * The model should identify the two domains being compared and map concepts between them. */ let sourceDomain = getParam("sourceDomain", ""); let targetDomain = getParam("targetDomain", ""); let mappings = parameters.mappings || []; let inferredInsights = parameters.inferredInsights || []; // If domains not provided, try to extract from prompt if (!sourceDomain || !targetDomain) { // Look for "X is like Y" patterns const analogyPatterns = [ /([\w\s]+)\s+is\s+like\s+([\w\s]+)/gi, /([\w\s]+)\s+resembles\s+([\w\s]+)/gi, /([\w\s]+)\s+similar\s+to\s+([\w\s]+)/gi, /compare\s+([\w\s]+)\s+(?:to|with)\s+([\w\s]+)/gi ]; for (const pattern of analogyPatterns) { const match = pattern.exec(prompt); if (match) { sourceDomain = match[1].trim(); targetDomain = match[2].trim(); break; } } // Fallback: split on common separators if (!sourceDomain || !targetDomain) { const parts = prompt.split(/\s+(?:and|vs|versus|compared to)\s+/i); if (parts.length >= 2) { sourceDomain = parts[0].trim(); targetDomain = parts[1].trim(); } } } // Generate mappings if none provided and both domains exist if (mappings.length === 0 && sourceDomain && targetDomain) { // Extract core nouns from both domains const extractNouns = (text) => { return text.toLowerCase() .replace(/[^a-z\s]/g, '') .split(/\s+/) .filter(word => word.length > 2