think_done
Complete structured reasoning sessions by verifying logic, identifying gaps, and exporting reports before finalizing complex problem solutions.
Instructions
Finish thinking session: verify logic and optionally export.
MANDATORY before final answer on complex problems.
Checks:
Low confidence thoughts in path
Unaddressed blockers
Ignored thoughts ratio
Options:
exportReport: Get markdown/json report (replaces export_session)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| winningPath | Yes | Thought numbers leading to solution | |
| summary | Yes | Final logic summary | |
| verdict | Yes | Ready for answer? | |
| constraintCheck | No | How constraints were addressed | |
| potentialFlaws | No | What could go wrong | |
| exportReport | No | Export format (optional) | |
| includeMermaid | No | Include diagram in export |
Implementation Reference
- src/index.ts:232-275 (handler)MCP tool handler for 'think_done': processes input args, calls thinkingService.consolidate for path verification and issue detection, formats output with status/READY or BLOCKED, progress metrics, warnings; optionally appends exported session report.server.registerTool('think_done', { title: 'Think Done', description: THINK_DONE_DESCRIPTION, inputSchema: thinkDoneSchema }, async (args) => { try { const result = thinkingService.consolidate({ winningPath: args.winningPath as number[], summary: args.summary as string, constraintCheck: args.constraintCheck as string | undefined, potentialFlaws: args.potentialFlaws as string | undefined, verdict: args.verdict as 'ready' | 'needs_more_work', }); if (result.status === 'error') { return { content: [{ type: 'text' as const, text: `Error: ${result.errorMessage}` }], isError: true }; } const pa = result.pathAnalysis; const issues = [ pa.lowConfidenceInPath.length > 0 ? `lowConf:#${pa.lowConfidenceInPath.join(',')}` : '', pa.unaddressedBlockers.length > 0 ? `blockers:#${pa.unaddressedBlockers.join(',')}` : '', ].filter(Boolean).join(' | '); let text = [ result.canProceedToFinalAnswer ? 'β READY' : 'π BLOCKED', `π Path: ${pa.pathLength}/${pa.totalThoughts} (${Math.round(pa.ignoredRatio * 100)}% ignored)`, issues ? `β οΈ ${issues}` : '', '', '--- STATUS ---', `verdict: ${result.canProceedToFinalAnswer ? 'READY' : 'BLOCKED'}`, ].filter(Boolean).join('\n'); // Export if requested (merged from export_session) if (args.exportReport) { const report = thinkingService.exportSession({ format: args.exportReport as 'markdown' | 'json', includeMermaid: (args.includeMermaid as boolean) ?? true, }); text += '\n\n--- EXPORT ---\n' + report; } return { content: [{ type: 'text' as const, text }] }; } catch (error) { return { content: [{ type: 'text' as const, text: `Error: ${error instanceof Error ? error.message : 'Unknown'}` }], isError: true }; } }
- src/index.ts:222-230 (schema)Zod input schema for 'think_done' tool, defining required winningPath, summary, verdict and optional fields for checks and export.const thinkDoneSchema = { winningPath: z.array(z.number().int().min(1)).describe('Thought numbers leading to solution'), summary: z.string().describe('Final logic summary'), verdict: z.enum(['ready', 'needs_more_work']).describe('Ready for answer?'), constraintCheck: z.string().optional().describe('How constraints were addressed'), potentialFlaws: z.string().optional().describe('What could go wrong'), exportReport: z.enum(['markdown', 'json']).optional().describe('Export format (optional)'), includeMermaid: z.boolean().optional().describe('Include diagram in export'), };
- src/index.ts:232-232 (registration)Registration of 'think_done' tool with McpServer, including title, description, and inputSchema.server.registerTool('think_done', { title: 'Think Done', description: THINK_DONE_DESCRIPTION, inputSchema: thinkDoneSchema },
- ConsolidateService.consolidate(): Primary helper implementing think_done logic - validates winning path connectivity, detects low-confidence thoughts in path, unaddressed blockers/critical extensions, high ignored ratio, path discontinuities; computes canProceedToFinalAnswer and pathAnalysis.consolidate( input: ConsolidateInput, sessionThoughts: ThoughtRecord[], onDeadEnd?: (path: number[], reason: string) => void, onSuccess?: (path: number[], summary: string) => void ): ConsolidateResult { const { winningPath, verdict } = input; const warnings: string[] = []; // Validate: must have thoughts to consolidate if (sessionThoughts.length === 0) { return { status: 'error', evaluation: 'Cannot consolidate empty thought history.', warnings: [], canProceedToFinalAnswer: false, pathAnalysis: { totalThoughts: 0, pathLength: 0, ignoredRatio: 0, lowConfidenceInPath: [], unaddressedBlockers: [], unaddressedCritical: [], }, errorMessage: 'No thoughts recorded. Use sequentialthinking first.', }; } // Validate: winning path must reference existing thoughts in current session const existingNumbers = new Set(sessionThoughts.map((t) => t.thoughtNumber)); const invalidRefs = winningPath.filter((n) => !existingNumbers.has(n)); if (invalidRefs.length > 0) { return { status: 'error', evaluation: `Invalid thought references in winning path: ${invalidRefs.join(', ')}`, warnings: [], canProceedToFinalAnswer: false, pathAnalysis: { totalThoughts: sessionThoughts.length, pathLength: winningPath.length, ignoredRatio: 0, lowConfidenceInPath: [], unaddressedBlockers: [], unaddressedCritical: [], }, errorMessage: `Thoughts ${invalidRefs.join(', ')} do not exist in current session.`, }; } // Validate: path connectivity - thoughts must be logically connected const connectivityCheck = this.validationService.validatePathConnectivity( winningPath, sessionThoughts ); if (!connectivityCheck.valid) { warnings.push(`π« PATH DISCONTINUITY: ${connectivityCheck.error}`); } // Find low-confidence thoughts in winning path const lowConfidenceInPath = sessionThoughts .filter((t) => winningPath.includes(t.thoughtNumber)) .filter((t) => t.confidence !== undefined && t.confidence < 5) .map((t) => t.thoughtNumber); if (lowConfidenceInPath.length > 0) { warnings.push( `β οΈ LOW CONFIDENCE: Your winning path includes thoughts with confidence < 5: #${lowConfidenceInPath.join(', ')}. Are you sure about these steps?` ); } // Check ignored thoughts ratio const ignoredRatio = 1 - winningPath.length / sessionThoughts.length; if (ignoredRatio > 0.6) { warnings.push( `β οΈ HIGH DISCARD RATE: You are ignoring ${Math.round(ignoredRatio * 100)}% of your thoughts. Ensure you haven't missed important contradictions in discarded branches.` ); } // Find unaddressed BLOCKER and HIGH impact critique extensions const unaddressedBlockers: number[] = []; const unaddressedCritical: number[] = []; for (const thought of sessionThoughts) { if (thought.extensions) { const hasBlocker = thought.extensions.some((e) => e.impact === 'blocker'); const hasHighCritique = thought.extensions.some( (e) => e.impact === 'high' && e.type === 'critique' ); if (winningPath.includes(thought.thoughtNumber)) { const hasRevision = sessionThoughts.some( (t) => t.isRevision && t.revisesThought === thought.thoughtNumber ); if (hasBlocker && !hasRevision) { unaddressedBlockers.push(thought.thoughtNumber); } if (hasHighCritique && !hasRevision) { unaddressedCritical.push(thought.thoughtNumber); } } } } if (unaddressedBlockers.length > 0) { warnings.push( `π« UNADDRESSED BLOCKERS: Thoughts #${unaddressedBlockers.join(', ')} have BLOCKER extensions but no revisions. You MUST address these before proceeding.` ); } if (unaddressedCritical.length > 0) { warnings.push( `β οΈ UNADDRESSED CRITICAL: Thoughts #${unaddressedCritical.join(', ')} have HIGH impact critiques but no revisions. Address these issues with isRevision: true.` ); } // Check for missing revisions in winningPath const missingRevisions: number[] = []; for (const thought of sessionThoughts) { if (!winningPath.includes(thought.thoughtNumber)) continue; if (!thought.extensions) continue; const hasCritical = thought.extensions.some( (e) => (e.impact === 'high' || e.impact === 'blocker') && e.type === 'critique' ); if (!hasCritical) continue; const revision = sessionThoughts.find( (t) => t.isRevision && t.revisesThought === thought.thoughtNumber ); if (revision && !winningPath.includes(revision.thoughtNumber)) { missingRevisions.push(thought.thoughtNumber); } } if (missingRevisions.length > 0) { warnings.push( `π« MISSING REVISIONS IN PATH: Thoughts #${missingRevisions.join(', ')} have critical critiques with revisions, but those revisions are NOT in your winningPath. Include the revision thoughts or remove the flawed originals.` ); } // Check for empty or too short winning path if (winningPath.length === 0) { warnings.push('β οΈ EMPTY PATH: No thoughts selected in winning path. This seems wrong.'); } else if (winningPath.length < 2 && sessionThoughts.length > 3) { warnings.push( 'β οΈ SUSPICIOUSLY SHORT PATH: Only 1 thought selected from a longer chain. Did you skip important reasoning?' ); } // Determine if can proceed const hasBlockerWarnings = unaddressedBlockers.length > 0; const hasCriticalWarnings = unaddressedCritical.length > 0; const hasMissingRevisions = missingRevisions.length > 0; const hasPathDiscontinuity = !connectivityCheck.valid; const canProceed = verdict === 'ready' && !hasBlockerWarnings && !hasCriticalWarnings && !hasMissingRevisions && !hasPathDiscontinuity && warnings.length <= 1; // Generate evaluation message let evaluation: string; if (canProceed) { evaluation = 'β SYNTHESIS ACCEPTED: Your reasoning chain is coherent. You may proceed to final answer.'; // v4.1.0: Save insight via callback on successful consolidation if (onSuccess) { onSuccess(winningPath, input.summary); } } else if (verdict === 'needs_more_work') { evaluation = 'π ACKNOWLEDGED: You identified this needs more work. Continue with sequentialthinking or extend_thought.'; // Record dead end via callback if (onDeadEnd) { onDeadEnd(winningPath, input.summary); } } else { evaluation = `β οΈ SYNTHESIS REJECTED: ${warnings.length} issue(s) found. Address them before providing final answer.`; } // Log consolidation console.error( `π― Consolidation: verdict=${verdict}, path=[${winningPath.join(',')}], warnings=${warnings.length}, canProceed=${canProceed}` ); return { status: 'success', evaluation, warnings, canProceedToFinalAnswer: canProceed, pathAnalysis: { totalThoughts: sessionThoughts.length, pathLength: winningPath.length, ignoredRatio: Math.round(ignoredRatio * 100) / 100, lowConfidenceInPath, unaddressedBlockers, unaddressedCritical, disconnectedAt: connectivityCheck.disconnectedAt ? [connectivityCheck.disconnectedAt] : undefined, }, }; }
- src/services/export.service.ts:30-57 (helper)ExportService.export(): Generates Markdown or JSON session reports including thoughts, extensions, branches, dead ends, Mermaid diagram; invoked optionally in think_done handler.export(data: ExportSessionData, options: ExportOptions = {}): string { const { format = 'markdown', includeMermaid = true } = options; const { thoughts, branches, deadEnds, sessionGoal, averageConfidence, mermaidDiagram } = data; if (thoughts.length === 0) { return format === 'json' ? JSON.stringify({ error: 'No thoughts recorded in current session' }) : '# Think Session Report\n\n*No thoughts recorded in current session.*'; } if (format === 'json') { return JSON.stringify( { goal: sessionGoal, thoughts, branches: Array.from(branches.entries()), deadEnds, averageConfidence, exportedAt: new Date().toISOString(), }, null, 2 ); } // Markdown format return this.generateMarkdown(data, includeMermaid); }