@gotza02/sequential-thinking 2026.3.9 ā 2026.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/ContextManager.d.ts +9 -0
- package/dist/core/ContextManager.js +62 -0
- package/dist/lib.d.ts +1 -0
- package/dist/lib.js +51 -3
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ThoughtData } from '../lib.js';
|
|
2
|
+
export declare class ContextManager {
|
|
3
|
+
private summaryCache;
|
|
4
|
+
constructor();
|
|
5
|
+
getOptimizedContext(history: ThoughtData[], currentBlockId: string | null): Promise<string>;
|
|
6
|
+
private compressOldBlocks;
|
|
7
|
+
private groupByBlock;
|
|
8
|
+
private generateSummary;
|
|
9
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export class ContextManager {
|
|
2
|
+
summaryCache = new Map();
|
|
3
|
+
constructor() { }
|
|
4
|
+
async getOptimizedContext(history, currentBlockId) {
|
|
5
|
+
// If no current block, treat everything as old or just show all?
|
|
6
|
+
// If null, we might be in setup mode. Let's assume empty current block.
|
|
7
|
+
const safeCurrentBlockId = currentBlockId || '';
|
|
8
|
+
const oldBlocks = history.filter(t => t.blockId !== safeCurrentBlockId);
|
|
9
|
+
const activeBlock = history.filter(t => t.blockId === safeCurrentBlockId);
|
|
10
|
+
const summaries = await this.compressOldBlocks(oldBlocks);
|
|
11
|
+
// Format active block detailed
|
|
12
|
+
const activeContext = activeBlock.map(t => `[${t.thoughtType?.toUpperCase() || 'INFO'}] #${t.thoughtNumber}: ${t.thought}`).join('\n');
|
|
13
|
+
return `
|
|
14
|
+
=== PROJECT HISTORY (SUMMARIZED) ===
|
|
15
|
+
${summaries}
|
|
16
|
+
|
|
17
|
+
=== CURRENT FOCUS (DETAILED: ${safeCurrentBlockId || 'GLOBAL'}) ===
|
|
18
|
+
${activeContext}
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
21
|
+
async compressOldBlocks(logs) {
|
|
22
|
+
const groups = this.groupByBlock(logs);
|
|
23
|
+
let result = '';
|
|
24
|
+
for (const [blockId, thoughts] of groups) {
|
|
25
|
+
// Skip blocks with undefined or empty blockId if they sneak in
|
|
26
|
+
if (!blockId)
|
|
27
|
+
continue;
|
|
28
|
+
const cached = this.summaryCache.get(blockId);
|
|
29
|
+
if (cached && cached.count === thoughts.length) {
|
|
30
|
+
result += `[Block: ${blockId}] Summary: ${cached.summary}\n`;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
if (thoughts.length > 2) {
|
|
34
|
+
const summary = await this.generateSummary(thoughts);
|
|
35
|
+
this.summaryCache.set(blockId, { summary, count: thoughts.length });
|
|
36
|
+
result += `[Block: ${blockId}] Summary: ${summary}\n`;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
result += `[Block: ${blockId}] ${thoughts.map(t => t.thought).join(' -> ')}\n`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
groupByBlock(logs) {
|
|
46
|
+
const map = new Map();
|
|
47
|
+
logs.forEach(log => {
|
|
48
|
+
const bid = log.blockId || 'default';
|
|
49
|
+
const items = map.get(bid) || [];
|
|
50
|
+
items.push(log);
|
|
51
|
+
map.set(bid, items);
|
|
52
|
+
});
|
|
53
|
+
return map;
|
|
54
|
+
}
|
|
55
|
+
async generateSummary(thoughts) {
|
|
56
|
+
// Mock implementation
|
|
57
|
+
const decisions = thoughts.filter(t => t.thoughtType === 'planning' || t.thoughtType === 'selection').length;
|
|
58
|
+
const executions = thoughts.filter(t => t.thoughtType === 'execution').length;
|
|
59
|
+
const topic = thoughts[0]?.thought.substring(0, 30) || 'Unknown';
|
|
60
|
+
return `Topic: "${topic}...". Processed ${thoughts.length} steps (${decisions} plans, ${executions} actions). Outcome: Handed off or completed.`;
|
|
61
|
+
}
|
|
62
|
+
}
|
package/dist/lib.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare class SequentialThinkingServer {
|
|
|
38
38
|
private saveMutex;
|
|
39
39
|
private consecutiveStallCount;
|
|
40
40
|
private confidenceScore;
|
|
41
|
+
private contextManager;
|
|
41
42
|
constructor(storagePath?: string, delayMs?: number);
|
|
42
43
|
private loadHistory;
|
|
43
44
|
private attemptRecovery;
|
package/dist/lib.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as fs from 'fs/promises';
|
|
|
3
3
|
import { existsSync, readFileSync } from 'fs';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { AsyncMutex } from './utils.js';
|
|
6
|
+
import { ContextManager } from './core/ContextManager.js';
|
|
6
7
|
export class SequentialThinkingServer {
|
|
7
8
|
thoughtHistory = [];
|
|
8
9
|
blocks = [];
|
|
@@ -15,6 +16,7 @@ export class SequentialThinkingServer {
|
|
|
15
16
|
saveMutex = new AsyncMutex();
|
|
16
17
|
consecutiveStallCount = 0; // Track consecutive stalls/loops
|
|
17
18
|
confidenceScore = 100; // Meta-Cognition Score (0-100)
|
|
19
|
+
contextManager = new ContextManager();
|
|
18
20
|
constructor(storagePath = 'thoughts_history.json', delayMs = 0) {
|
|
19
21
|
this.disableThoughtLogging = (process.env.DISABLE_THOUGHT_LOGGING || "").toLowerCase() === "true";
|
|
20
22
|
this.storagePath = path.resolve(storagePath);
|
|
@@ -437,6 +439,13 @@ ${typeof wrappedThought === 'string' && wrappedThought.startsWith('ā') ? wrapp
|
|
|
437
439
|
const complexity = input.complexity || 'medium';
|
|
438
440
|
const warnings = [];
|
|
439
441
|
let feedbackExtension = "";
|
|
442
|
+
// --- š FEATURE 0: Smart Branching Reward (Reset Confidence on Pivot) ---
|
|
443
|
+
if (input.branchFromThought) {
|
|
444
|
+
if (this.confidenceScore < 75) {
|
|
445
|
+
this.confidenceScore = 75;
|
|
446
|
+
feedbackExtension += `\nšæ BRANCH DETECTED: Confidence restored to 75. Good decision to pivot.`;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
440
449
|
// --- š§ FEATURE 1: Semantic Thought Recall ---
|
|
441
450
|
if (input.thoughtType === 'analysis') {
|
|
442
451
|
const previousSolution = await this.findSolution(input.thought);
|
|
@@ -444,14 +453,50 @@ ${typeof wrappedThought === 'string' && wrappedThought.startsWith('ā') ? wrapp
|
|
|
444
453
|
feedbackExtension += `\nš” RECALL: I found a similar past solution for '${previousSolution.topic}'.\nTry these steps: ${previousSolution.solution.substring(0, 100)}...`;
|
|
445
454
|
}
|
|
446
455
|
}
|
|
447
|
-
// ---
|
|
456
|
+
// --- ā FEATURE 1.5: Anti-Insanity (Prevent Repeating Failed Executions) ---
|
|
457
|
+
const historyForCheck = this.thoughtHistory.filter(t => t.blockId === input.blockId || (input.blockId === this.currentBlockId && t.blockId === this.currentBlockId));
|
|
458
|
+
if (input.thoughtType === 'execution') {
|
|
459
|
+
const failedExecutions = historyForCheck.filter((t, index) => {
|
|
460
|
+
if (t.thoughtType !== 'execution')
|
|
461
|
+
return false;
|
|
462
|
+
// Find the observation immediately following this execution
|
|
463
|
+
// Note: This relies on thoughtNumber order
|
|
464
|
+
const nextThought = this.thoughtHistory.find(h => h.thoughtNumber === t.thoughtNumber + 1);
|
|
465
|
+
if (nextThought && nextThought.thoughtType === 'observation') {
|
|
466
|
+
const result = nextThought.toolResult?.toLowerCase() || "";
|
|
467
|
+
// Check for failure signals
|
|
468
|
+
return result.includes("error") || result.includes("fail") || result.includes("exception") || result.includes("enoent");
|
|
469
|
+
}
|
|
470
|
+
return false;
|
|
471
|
+
});
|
|
472
|
+
const isRepeatedFailure = failedExecutions.some(t => t.thought.trim() === input.thought.trim());
|
|
473
|
+
if (isRepeatedFailure) {
|
|
474
|
+
const failedItem = failedExecutions.find(t => t.thought.trim() === input.thought.trim());
|
|
475
|
+
warnings.push(`ā INSANITY CHECK: You are trying to run a command that ALREADY FAILED in thought #${failedItem?.thoughtNumber}. STOP. Do not repeat mistakes. Try a different parameter or tool.`);
|
|
476
|
+
this.confidenceScore -= 15;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
// --- š FEATURE 4: Meta-Cognition Score Check (Reflexion Mandate & Smart Branching) ---
|
|
448
480
|
if (this.confidenceScore < 50 && input.thoughtType !== 'reflexion' && input.thoughtType !== 'analysis') {
|
|
481
|
+
// Smart Branching: Find the last valid planning point
|
|
482
|
+
const lastGoodPlan = historyForCheck
|
|
483
|
+
.slice()
|
|
484
|
+
.reverse()
|
|
485
|
+
.find(t => t.thoughtType === 'planning' || t.thoughtType === 'hypothesis');
|
|
486
|
+
const recoveryAdvice = lastGoodPlan
|
|
487
|
+
? `RECOMMENDATION: Branch from thought #${lastGoodPlan.thoughtNumber} to try a new approach.`
|
|
488
|
+
: `RECOMMENDATION: Use 'reflexion' to analyze why current attempts are failing.`;
|
|
449
489
|
return {
|
|
450
490
|
content: [{
|
|
451
491
|
type: "text",
|
|
452
492
|
text: JSON.stringify({
|
|
453
493
|
status: "CRITICAL_STOP",
|
|
454
|
-
feedback: [
|
|
494
|
+
feedback: [
|
|
495
|
+
"šØ CONFIDENCE CRITICAL (<50). Execution blocked to prevent further damage.",
|
|
496
|
+
"š STOP: You are likely in a loop or making repeated errors.",
|
|
497
|
+
"š REQUIRED ACTION: You must switch thoughtType to 'reflexion' to critique your errors.",
|
|
498
|
+
recoveryAdvice
|
|
499
|
+
],
|
|
455
500
|
confidenceScore: this.confidenceScore
|
|
456
501
|
}, null, 2)
|
|
457
502
|
}],
|
|
@@ -523,7 +568,8 @@ ${typeof wrappedThought === 'string' && wrappedThought.startsWith('ā') ? wrapp
|
|
|
523
568
|
// Rule 3: Missing Observation
|
|
524
569
|
if (lastThought &&
|
|
525
570
|
lastThought.thoughtType === 'execution' &&
|
|
526
|
-
input.thoughtType !== 'observation'
|
|
571
|
+
input.thoughtType !== 'observation' &&
|
|
572
|
+
!input.branchFromThought) {
|
|
527
573
|
warnings.push(`š” INTERLEAVED HINT: Your last step was 'execution'. The next step SHOULD be 'observation' to record and analyze the tool result before continuing.`);
|
|
528
574
|
}
|
|
529
575
|
// Rule 4: Skipping Planning (Adaptive)
|
|
@@ -637,6 +683,7 @@ ${typeof wrappedThought === 'string' && wrappedThought.startsWith('ā') ? wrapp
|
|
|
637
683
|
// D. Generate Contextual Output
|
|
638
684
|
const currentBlock = this.blocks.find(b => b.id === input.blockId);
|
|
639
685
|
const mermaid = this.generateMermaid();
|
|
686
|
+
const optimizedContext = await this.contextManager.getOptimizedContext(this.thoughtHistory, input.blockId || null);
|
|
640
687
|
if (feedbackExtension)
|
|
641
688
|
warnings.push(feedbackExtension);
|
|
642
689
|
return {
|
|
@@ -650,6 +697,7 @@ ${typeof wrappedThought === 'string' && wrappedThought.startsWith('ā') ? wrapp
|
|
|
650
697
|
blockContext: currentBlock
|
|
651
698
|
? `Block '${currentBlock.topic.substring(0, 30)}' has ${currentBlock.thoughts.length} thoughts.`
|
|
652
699
|
: 'No active block',
|
|
700
|
+
optimizedContext,
|
|
653
701
|
branches: Object.keys(this.branches),
|
|
654
702
|
thoughtHistoryLength: this.thoughtHistory.length,
|
|
655
703
|
feedback: warnings.length > 0 ? warnings : "Flow Healthy ā
",
|