@gotza02/sequential-thinking 2026.2.20 → 2026.2.22
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/README.md +1 -0
- package/dist/codestore.d.ts +28 -0
- package/dist/graph.d.ts +60 -0
- package/dist/graph.js +19 -0
- package/dist/http-server.d.ts +2 -0
- package/dist/http-server.js +7 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/lib.d.ts +67 -0
- package/dist/lib.js +323 -83
- package/dist/notes.d.ts +25 -0
- package/dist/system_test.d.ts +1 -0
- package/dist/test_ts_req.d.ts +1 -0
- package/dist/tools/codestore.d.ts +3 -0
- package/dist/tools/coding.d.ts +3 -0
- package/dist/tools/filesystem.d.ts +2 -0
- package/dist/tools/graph.d.ts +3 -0
- package/dist/tools/graph.js +18 -0
- package/dist/tools/human.d.ts +65 -0
- package/dist/tools/human.js +305 -0
- package/dist/tools/notes.d.ts +3 -0
- package/dist/tools/thinking.d.ts +3 -0
- package/dist/tools/thinking.js +137 -65
- package/dist/tools/web.d.ts +2 -0
- package/dist/utils.d.ts +32 -0
- package/package.json +3 -1
- package/dist/chaos.test.js +0 -72
- package/dist/codestore.test.js +0 -59
- package/dist/coding.test.js +0 -140
- package/dist/e2e.test.js +0 -122
- package/dist/filesystem.test.js +0 -189
- package/dist/graph.test.js +0 -150
- package/dist/graph_repro.test.js +0 -63
- package/dist/integration.test.js +0 -58
- package/dist/notes.test.js +0 -74
- package/dist/registration.test.js +0 -39
- package/dist/repro_dollar.js +0 -30
- package/dist/repro_dollar_simple.js +0 -22
- package/dist/repro_history.js +0 -41
- package/dist/repro_path.js +0 -17
- package/dist/repro_search.test.js +0 -79
- package/dist/repro_ts_req.js +0 -3
- package/dist/server.test.js +0 -127
- package/dist/stress.test.js +0 -68
- package/dist/utils.test.js +0 -40
- package/dist/verify_cache.test.js +0 -27
- package/dist/verify_edit.test.js +0 -66
- package/dist/verify_notes.test.js +0 -36
- package/dist/verify_viz.test.js +0 -25
- package/dist/web_fallback.test.js +0 -103
- package/dist/web_read.test.js +0 -60
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/**
|
|
3
|
+
* Human-in-the-Loop interaction record
|
|
4
|
+
*/
|
|
5
|
+
interface HumanInteraction {
|
|
6
|
+
id: string;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
questionType: 'confirmation' | 'choice' | 'input' | 'review';
|
|
9
|
+
urgency: 'low' | 'medium' | 'high' | 'critical';
|
|
10
|
+
question: string;
|
|
11
|
+
context?: string;
|
|
12
|
+
options?: string[];
|
|
13
|
+
defaultOption?: string;
|
|
14
|
+
status: 'pending' | 'answered' | 'timeout' | 'skipped';
|
|
15
|
+
response?: string;
|
|
16
|
+
respondedAt?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Human-in-the-Loop Manager
|
|
20
|
+
* Manages interactions between AI and human operators
|
|
21
|
+
*/
|
|
22
|
+
export declare class HumanInteractionManager {
|
|
23
|
+
private interactions;
|
|
24
|
+
private pendingCallbacks;
|
|
25
|
+
constructor();
|
|
26
|
+
/**
|
|
27
|
+
* Generate unique interaction ID
|
|
28
|
+
*/
|
|
29
|
+
private generateId;
|
|
30
|
+
/**
|
|
31
|
+
* Create a new human interaction request
|
|
32
|
+
*/
|
|
33
|
+
createInteraction(params: {
|
|
34
|
+
questionType: 'confirmation' | 'choice' | 'input' | 'review';
|
|
35
|
+
urgency: 'low' | 'medium' | 'high' | 'critical';
|
|
36
|
+
question: string;
|
|
37
|
+
context?: string;
|
|
38
|
+
options?: string[];
|
|
39
|
+
defaultOption?: string;
|
|
40
|
+
timeoutMs?: number;
|
|
41
|
+
}): Promise<HumanInteraction>;
|
|
42
|
+
/**
|
|
43
|
+
* Record a response to an interaction
|
|
44
|
+
*/
|
|
45
|
+
recordResponse(id: string, response: string): HumanInteraction | null;
|
|
46
|
+
/**
|
|
47
|
+
* Get all pending interactions
|
|
48
|
+
*/
|
|
49
|
+
getPendingInteractions(): HumanInteraction[];
|
|
50
|
+
/**
|
|
51
|
+
* Get interaction history
|
|
52
|
+
*/
|
|
53
|
+
getHistory(limit?: number): HumanInteraction[];
|
|
54
|
+
/**
|
|
55
|
+
* Clear old interactions (older than specified hours)
|
|
56
|
+
*/
|
|
57
|
+
clearOldInteractions(hoursOld?: number): number;
|
|
58
|
+
/**
|
|
59
|
+
* Format interaction for display
|
|
60
|
+
*/
|
|
61
|
+
formatInteraction(interaction: HumanInteraction): string;
|
|
62
|
+
}
|
|
63
|
+
export declare function getHumanManager(): HumanInteractionManager;
|
|
64
|
+
export declare function registerHumanTools(server: McpServer): void;
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Human-in-the-Loop Manager
|
|
4
|
+
* Manages interactions between AI and human operators
|
|
5
|
+
*/
|
|
6
|
+
export class HumanInteractionManager {
|
|
7
|
+
interactions = new Map();
|
|
8
|
+
pendingCallbacks = new Map();
|
|
9
|
+
constructor() { }
|
|
10
|
+
/**
|
|
11
|
+
* Generate unique interaction ID
|
|
12
|
+
*/
|
|
13
|
+
generateId() {
|
|
14
|
+
return `hitl_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a new human interaction request
|
|
18
|
+
*/
|
|
19
|
+
async createInteraction(params) {
|
|
20
|
+
const id = this.generateId();
|
|
21
|
+
const interaction = {
|
|
22
|
+
id,
|
|
23
|
+
timestamp: new Date().toISOString(),
|
|
24
|
+
questionType: params.questionType,
|
|
25
|
+
urgency: params.urgency,
|
|
26
|
+
question: params.question,
|
|
27
|
+
context: params.context,
|
|
28
|
+
options: params.options,
|
|
29
|
+
defaultOption: params.defaultOption,
|
|
30
|
+
status: 'pending'
|
|
31
|
+
};
|
|
32
|
+
this.interactions.set(id, interaction);
|
|
33
|
+
return interaction;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Record a response to an interaction
|
|
37
|
+
*/
|
|
38
|
+
recordResponse(id, response) {
|
|
39
|
+
const interaction = this.interactions.get(id);
|
|
40
|
+
if (!interaction)
|
|
41
|
+
return null;
|
|
42
|
+
interaction.status = 'answered';
|
|
43
|
+
interaction.response = response;
|
|
44
|
+
interaction.respondedAt = new Date().toISOString();
|
|
45
|
+
// Resolve any pending callback
|
|
46
|
+
const callback = this.pendingCallbacks.get(id);
|
|
47
|
+
if (callback) {
|
|
48
|
+
clearTimeout(callback.timeout);
|
|
49
|
+
callback.resolve(response);
|
|
50
|
+
this.pendingCallbacks.delete(id);
|
|
51
|
+
}
|
|
52
|
+
return interaction;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get all pending interactions
|
|
56
|
+
*/
|
|
57
|
+
getPendingInteractions() {
|
|
58
|
+
return Array.from(this.interactions.values())
|
|
59
|
+
.filter(i => i.status === 'pending')
|
|
60
|
+
.sort((a, b) => {
|
|
61
|
+
// Sort by urgency then by timestamp
|
|
62
|
+
const urgencyOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
63
|
+
const urgencyDiff = urgencyOrder[a.urgency] - urgencyOrder[b.urgency];
|
|
64
|
+
if (urgencyDiff !== 0)
|
|
65
|
+
return urgencyDiff;
|
|
66
|
+
return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get interaction history
|
|
71
|
+
*/
|
|
72
|
+
getHistory(limit = 50) {
|
|
73
|
+
return Array.from(this.interactions.values())
|
|
74
|
+
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
|
|
75
|
+
.slice(0, limit);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Clear old interactions (older than specified hours)
|
|
79
|
+
*/
|
|
80
|
+
clearOldInteractions(hoursOld = 24) {
|
|
81
|
+
const cutoff = Date.now() - (hoursOld * 60 * 60 * 1000);
|
|
82
|
+
let cleared = 0;
|
|
83
|
+
for (const [id, interaction] of this.interactions) {
|
|
84
|
+
if (new Date(interaction.timestamp).getTime() < cutoff) {
|
|
85
|
+
this.interactions.delete(id);
|
|
86
|
+
cleared++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return cleared;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Format interaction for display
|
|
93
|
+
*/
|
|
94
|
+
formatInteraction(interaction) {
|
|
95
|
+
const urgencyEmoji = {
|
|
96
|
+
critical: '🚨',
|
|
97
|
+
high: '⚠️',
|
|
98
|
+
medium: '📋',
|
|
99
|
+
low: 'ℹ️'
|
|
100
|
+
};
|
|
101
|
+
const typeLabel = {
|
|
102
|
+
confirmation: 'ยืนยัน (Yes/No)',
|
|
103
|
+
choice: 'เลือกตัวเลือก',
|
|
104
|
+
input: 'ต้องการข้อมูล',
|
|
105
|
+
review: 'ตรวจสอบ/อนุมัติ'
|
|
106
|
+
};
|
|
107
|
+
let output = `\n${'═'.repeat(60)}\n`;
|
|
108
|
+
output += `${urgencyEmoji[interaction.urgency]} HUMAN INPUT REQUIRED [${interaction.urgency.toUpperCase()}]\n`;
|
|
109
|
+
output += `${'─'.repeat(60)}\n`;
|
|
110
|
+
output += `📌 Type: ${typeLabel[interaction.questionType]}\n`;
|
|
111
|
+
output += `🆔 ID: ${interaction.id}\n`;
|
|
112
|
+
output += `⏰ Time: ${interaction.timestamp}\n`;
|
|
113
|
+
output += `${'─'.repeat(60)}\n`;
|
|
114
|
+
output += `❓ Question:\n ${interaction.question}\n`;
|
|
115
|
+
if (interaction.context) {
|
|
116
|
+
output += `\n📝 Context:\n ${interaction.context}\n`;
|
|
117
|
+
}
|
|
118
|
+
if (interaction.options && interaction.options.length > 0) {
|
|
119
|
+
output += `\n📋 Options:\n`;
|
|
120
|
+
interaction.options.forEach((opt, i) => {
|
|
121
|
+
const isDefault = opt === interaction.defaultOption;
|
|
122
|
+
output += ` ${i + 1}. ${opt}${isDefault ? ' (default)' : ''}\n`;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (interaction.defaultOption && interaction.questionType === 'confirmation') {
|
|
126
|
+
output += `\n Default: ${interaction.defaultOption}\n`;
|
|
127
|
+
}
|
|
128
|
+
output += `${'═'.repeat(60)}\n`;
|
|
129
|
+
output += `💡 To respond, use: respond_to_human tool with id="${interaction.id}"\n`;
|
|
130
|
+
return output;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Singleton instance for the manager
|
|
134
|
+
let humanManager = null;
|
|
135
|
+
export function getHumanManager() {
|
|
136
|
+
if (!humanManager) {
|
|
137
|
+
humanManager = new HumanInteractionManager();
|
|
138
|
+
}
|
|
139
|
+
return humanManager;
|
|
140
|
+
}
|
|
141
|
+
export function registerHumanTools(server) {
|
|
142
|
+
const manager = getHumanManager();
|
|
143
|
+
// --- ask_human Tool ---
|
|
144
|
+
server.tool("ask_human", `Request human input or decision during AI operation. Use this tool when:
|
|
145
|
+
- A destructive or irreversible action needs confirmation (e.g., "Delete database?")
|
|
146
|
+
- Multiple valid approaches exist and human preference is needed
|
|
147
|
+
- Critical decisions that could have significant impact
|
|
148
|
+
- Clarification is needed on ambiguous requirements
|
|
149
|
+
- Review/approval is required before proceeding
|
|
150
|
+
|
|
151
|
+
This transforms the AI from "guessing" to "collaborative" mode.
|
|
152
|
+
|
|
153
|
+
Question Types:
|
|
154
|
+
- confirmation: Yes/No questions (e.g., "Proceed with deletion?")
|
|
155
|
+
- choice: Select from predefined options (e.g., "Which framework?")
|
|
156
|
+
- input: Free-form text input needed (e.g., "What should the function be named?")
|
|
157
|
+
- review: Present work for human review/approval
|
|
158
|
+
|
|
159
|
+
Urgency Levels:
|
|
160
|
+
- critical: Immediate response required, blocks all operations
|
|
161
|
+
- high: Important decision, should respond soon
|
|
162
|
+
- medium: Normal priority question
|
|
163
|
+
- low: Nice to have input, can proceed with default if no response`, {
|
|
164
|
+
question: z.string().describe("The question to ask the human"),
|
|
165
|
+
questionType: z.enum(['confirmation', 'choice', 'input', 'review'])
|
|
166
|
+
.default('input')
|
|
167
|
+
.describe("Type of question being asked"),
|
|
168
|
+
urgency: z.enum(['low', 'medium', 'high', 'critical'])
|
|
169
|
+
.default('medium')
|
|
170
|
+
.describe("Urgency level of the question"),
|
|
171
|
+
context: z.string().optional()
|
|
172
|
+
.describe("Additional context explaining why this input is needed"),
|
|
173
|
+
options: z.array(z.string()).optional()
|
|
174
|
+
.describe("Available options for 'choice' type questions"),
|
|
175
|
+
defaultOption: z.string().optional()
|
|
176
|
+
.describe("Default option if human doesn't respond (for non-critical)")
|
|
177
|
+
}, async ({ question, questionType, urgency, context, options, defaultOption }) => {
|
|
178
|
+
// Validate options for choice type
|
|
179
|
+
if (questionType === 'choice' && (!options || options.length < 2)) {
|
|
180
|
+
return {
|
|
181
|
+
content: [{
|
|
182
|
+
type: "text",
|
|
183
|
+
text: "Error: 'choice' question type requires at least 2 options"
|
|
184
|
+
}],
|
|
185
|
+
isError: true
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const interaction = await manager.createInteraction({
|
|
189
|
+
questionType,
|
|
190
|
+
urgency,
|
|
191
|
+
question,
|
|
192
|
+
context,
|
|
193
|
+
options,
|
|
194
|
+
defaultOption
|
|
195
|
+
});
|
|
196
|
+
const formatted = manager.formatInteraction(interaction);
|
|
197
|
+
return {
|
|
198
|
+
content: [{
|
|
199
|
+
type: "text",
|
|
200
|
+
text: formatted + `\n\n⏳ Status: WAITING FOR HUMAN RESPONSE\n\nThe AI should pause this line of action until a response is received via 'respond_to_human' or 'get_pending_questions'.`
|
|
201
|
+
}]
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
// --- respond_to_human Tool ---
|
|
205
|
+
server.tool("respond_to_human", "Provide a response to a pending human-in-the-loop question. Use this after receiving human input.", {
|
|
206
|
+
interactionId: z.string().describe("The interaction ID from ask_human"),
|
|
207
|
+
response: z.string().describe("The human's response to the question")
|
|
208
|
+
}, async ({ interactionId, response }) => {
|
|
209
|
+
const interaction = manager.recordResponse(interactionId, response);
|
|
210
|
+
if (!interaction) {
|
|
211
|
+
return {
|
|
212
|
+
content: [{
|
|
213
|
+
type: "text",
|
|
214
|
+
text: `Error: No pending interaction found with ID "${interactionId}"`
|
|
215
|
+
}],
|
|
216
|
+
isError: true
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
content: [{
|
|
221
|
+
type: "text",
|
|
222
|
+
text: `✅ Response recorded for interaction ${interactionId}\n\n` +
|
|
223
|
+
`Question: ${interaction.question}\n` +
|
|
224
|
+
`Response: ${response}\n` +
|
|
225
|
+
`Responded at: ${interaction.respondedAt}\n\n` +
|
|
226
|
+
`The AI can now proceed based on this human decision.`
|
|
227
|
+
}]
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
// --- get_pending_questions Tool ---
|
|
231
|
+
server.tool("get_pending_questions", "Get all pending human-in-the-loop questions that need responses.", {}, async () => {
|
|
232
|
+
const pending = manager.getPendingInteractions();
|
|
233
|
+
if (pending.length === 0) {
|
|
234
|
+
return {
|
|
235
|
+
content: [{
|
|
236
|
+
type: "text",
|
|
237
|
+
text: "✅ No pending questions. All human interactions have been addressed."
|
|
238
|
+
}]
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
let output = `📋 PENDING HUMAN INTERACTIONS (${pending.length})\n`;
|
|
242
|
+
output += `${'═'.repeat(60)}\n\n`;
|
|
243
|
+
for (const interaction of pending) {
|
|
244
|
+
output += manager.formatInteraction(interaction);
|
|
245
|
+
output += '\n';
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
content: [{
|
|
249
|
+
type: "text",
|
|
250
|
+
text: output
|
|
251
|
+
}]
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
// --- get_interaction_history Tool ---
|
|
255
|
+
server.tool("get_interaction_history", "Get the history of human-AI interactions for context and learning.", {
|
|
256
|
+
limit: z.number().int().min(1).max(100).default(20)
|
|
257
|
+
.describe("Maximum number of interactions to return")
|
|
258
|
+
}, async ({ limit }) => {
|
|
259
|
+
const history = manager.getHistory(limit);
|
|
260
|
+
if (history.length === 0) {
|
|
261
|
+
return {
|
|
262
|
+
content: [{
|
|
263
|
+
type: "text",
|
|
264
|
+
text: "No interaction history found."
|
|
265
|
+
}]
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
let output = `📜 INTERACTION HISTORY (${history.length} most recent)\n`;
|
|
269
|
+
output += `${'═'.repeat(60)}\n\n`;
|
|
270
|
+
for (const interaction of history) {
|
|
271
|
+
const statusEmoji = {
|
|
272
|
+
pending: '⏳',
|
|
273
|
+
answered: '✅',
|
|
274
|
+
timeout: '⏱️',
|
|
275
|
+
skipped: '⏭️'
|
|
276
|
+
};
|
|
277
|
+
output += `${statusEmoji[interaction.status]} [${interaction.id}]\n`;
|
|
278
|
+
output += ` Type: ${interaction.questionType} | Urgency: ${interaction.urgency}\n`;
|
|
279
|
+
output += ` Q: ${interaction.question.substring(0, 80)}${interaction.question.length > 80 ? '...' : ''}\n`;
|
|
280
|
+
if (interaction.response) {
|
|
281
|
+
output += ` A: ${interaction.response.substring(0, 80)}${interaction.response.length > 80 ? '...' : ''}\n`;
|
|
282
|
+
}
|
|
283
|
+
output += ` Time: ${interaction.timestamp}\n\n`;
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
content: [{
|
|
287
|
+
type: "text",
|
|
288
|
+
text: output
|
|
289
|
+
}]
|
|
290
|
+
};
|
|
291
|
+
});
|
|
292
|
+
// --- clear_old_interactions Tool ---
|
|
293
|
+
server.tool("clear_old_interactions", "Clear old interaction history to free up memory.", {
|
|
294
|
+
hoursOld: z.number().int().min(1).default(24)
|
|
295
|
+
.describe("Clear interactions older than this many hours")
|
|
296
|
+
}, async ({ hoursOld }) => {
|
|
297
|
+
const cleared = manager.clearOldInteractions(hoursOld);
|
|
298
|
+
return {
|
|
299
|
+
content: [{
|
|
300
|
+
type: "text",
|
|
301
|
+
text: `🗑️ Cleared ${cleared} interactions older than ${hoursOld} hours.`
|
|
302
|
+
}]
|
|
303
|
+
};
|
|
304
|
+
});
|
|
305
|
+
}
|
package/dist/tools/thinking.js
CHANGED
|
@@ -1,71 +1,94 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export function registerThinkingTools(server, thinkingServer) {
|
|
3
|
-
// --- Sequential Thinking Tool ---
|
|
4
|
-
server.tool("sequentialthinking", `
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
// --- Sequential Thinking Tool (Opus 4.5 Interleaved Mode) ---
|
|
4
|
+
server.tool("sequentialthinking", `CORE THINKING ENGINE (OPUS-4.5 INTERLEAVED MODE).
|
|
5
|
+
Use this tool to structure your reasoning, plan actions, and analyze results.
|
|
6
|
+
The system is now BLOCK-BASED to handle complex, multi-stage tasks.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
8
|
+
═══════════════════════════════════════════════════════════════
|
|
9
|
+
THOUGHT TYPES (NEW)
|
|
10
|
+
═══════════════════════════════════════════════════════════════
|
|
11
|
+
- 'analysis' : Understand the problem / Break down requirements
|
|
12
|
+
- 'planning' : Formulate a plan / Decide next steps BEFORE executing
|
|
13
|
+
- 'execution' : Explicitly state what tool you are about to call
|
|
14
|
+
- 'observation' : Record the OUTPUT of a tool call (MANDATORY after execution)
|
|
15
|
+
- 'hypothesis' : Form a new hypothesis based on observations
|
|
16
|
+
- 'reflexion' : Critique your progress / Check for errors / Self-review
|
|
17
|
+
- 'solution' : Final answer / Task completion
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
- Problems where the full scope might not be clear initially
|
|
20
|
-
- Problems that require a multi-step solution
|
|
21
|
-
- Tasks that need to maintain context over multiple steps
|
|
22
|
-
- Situations where irrelevant information needs to be filtered out
|
|
19
|
+
Legacy types (still supported):
|
|
20
|
+
- 'generation' : Generate multiple options
|
|
21
|
+
- 'evaluation' : Evaluate options with scoring
|
|
22
|
+
- 'selection' : Select the best option
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- Branch Merging: Combine insights from multiple divergent paths.
|
|
24
|
+
═══════════════════════════════════════════════════════════════
|
|
25
|
+
INTERLEAVED WORKFLOW RULE (CRITICAL)
|
|
26
|
+
═══════════════════════════════════════════════════════════════
|
|
27
|
+
The correct flow is:
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
- If you realize you are stuck in a loop or a bug persists after 2 attempts:
|
|
32
|
-
1. Do NOT continue linear thoughts.
|
|
33
|
-
2. Create a NEW BRANCH ('branchFromThought') from a point before the error.
|
|
34
|
-
3. Explicitly state "Stuck detected, branching to explore Approach B".
|
|
35
|
-
4. Change your fundamental assumptions or implementation strategy completely.
|
|
29
|
+
Analysis -> Planning -> Execution -> [Call Tool] -> Observation -> Analysis -> ...
|
|
36
30
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- thoughtNumber: Current number in sequence.
|
|
41
|
-
- totalThoughts: Current estimate of thoughts needed (can be adjusted).
|
|
42
|
-
- isRevision: True if this thought revises previous thinking.
|
|
43
|
-
- revisesThought: Which thought number is being reconsidered.
|
|
44
|
-
- branchFromThought: The branching point thought number.
|
|
45
|
-
- branchId: Identifier for the current branch.
|
|
46
|
-
- thoughtType: The type of thought (analysis, generation, evaluation, reflexion, selection).
|
|
47
|
-
- score: Score for evaluation (1-10).
|
|
48
|
-
- options: List of options generated.
|
|
49
|
-
- selectedOption: The option selected.
|
|
31
|
+
1. BEFORE calling any tool, use 'execution' type to declare your intent
|
|
32
|
+
2. AFTER a tool returns, use 'observation' type to record and analyze the result
|
|
33
|
+
3. The system will WARN you if you skip the observation step
|
|
50
34
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
35
|
+
Example flow:
|
|
36
|
+
T1: analysis - "I need to read the config file to understand the structure"
|
|
37
|
+
T2: planning - "I will use read_file tool on config.json"
|
|
38
|
+
T3: execution - "Calling read_file on ./config.json" [relatedToolCall: "read_file"]
|
|
39
|
+
[Tool Call: read_file]
|
|
40
|
+
T4: observation - "The config has 3 sections: auth, database, logging" [toolResult: "..."]
|
|
41
|
+
T5: analysis - "Now I need to modify the database section"
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
═══════════════════════════════════════════════════════════════
|
|
45
|
+
BLOCKS (Context Grouping)
|
|
46
|
+
═══════════════════════════════════════════════════════════════
|
|
47
|
+
Thoughts are grouped into 'blocks' by topic. When switching topics:
|
|
48
|
+
- Start a new block with a new blockId (e.g., 'debug-auth', 'implement-api')
|
|
49
|
+
- This prevents false-positive loop detection when changing context
|
|
50
|
+
- Old blocks are auto-archived to save memory
|
|
51
|
+
|
|
52
|
+
═══════════════════════════════════════════════════════════════
|
|
53
|
+
SMART WARNINGS
|
|
54
|
+
═══════════════════════════════════════════════════════════════
|
|
55
|
+
The system will warn you when:
|
|
56
|
+
- STALLING: Too many thinking steps without execution
|
|
57
|
+
- LOOP: Repeating the same action
|
|
58
|
+
- MISSING OBSERVATION: Skipping result analysis after tool call
|
|
59
|
+
- NO PLANNING: Executing without a planning step
|
|
60
|
+
- NO VERIFICATION: Ending without testing/checking
|
|
61
|
+
|
|
62
|
+
═══════════════════════════════════════════════════════════════
|
|
63
|
+
TROUBLESHOOTING
|
|
64
|
+
═══════════════════════════════════════════════════════════════
|
|
65
|
+
If stuck in a loop:
|
|
66
|
+
1. Do NOT continue linear thoughts
|
|
67
|
+
2. Create a NEW BRANCH ('branchFromThought') from before the error
|
|
68
|
+
3. State "Stuck detected, branching to explore Approach B"
|
|
69
|
+
4. Change your assumptions completely`, {
|
|
56
70
|
thought: z.string().describe("Your current thinking step"),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
thoughtType: z.enum([
|
|
72
|
+
'analysis', 'planning', 'execution', 'observation',
|
|
73
|
+
'hypothesis', 'reflexion', 'solution',
|
|
74
|
+
'generation', 'evaluation', 'selection'
|
|
75
|
+
]).describe("The structural role of this thought (see THOUGHT TYPES above)"),
|
|
76
|
+
thoughtNumber: z.number().int().min(1).describe("Current thought number (e.g., 1, 2, 3)"),
|
|
77
|
+
totalThoughts: z.number().int().min(1).describe("Estimated total thoughts needed (can be adjusted)"),
|
|
78
|
+
nextThoughtNeeded: z.boolean().describe("True if more thinking/action is needed"),
|
|
79
|
+
// New Interleaved Fields
|
|
80
|
+
blockId: z.string().optional().describe("ID for the current topic block (e.g., 'auth-debug', 'api-research'). Keep same ID to stay in context."),
|
|
81
|
+
relatedToolCall: z.string().optional().describe("If type='execution', specify the tool name here (e.g., 'read_file', 'edit_file')"),
|
|
82
|
+
toolResult: z.string().optional().describe("If type='observation', summarize the key findings from the tool output here"),
|
|
83
|
+
// Legacy Fields (backwards compatible)
|
|
60
84
|
isRevision: z.boolean().optional().describe("Whether this revises previous thinking"),
|
|
61
|
-
revisesThought: z.number().int().min(1).optional().describe("Which thought is being reconsidered"),
|
|
85
|
+
revisesThought: z.number().int().min(1).optional().describe("Which thought number is being reconsidered"),
|
|
62
86
|
branchFromThought: z.number().int().min(1).optional().describe("Branching point thought number"),
|
|
63
|
-
branchId: z.string().optional().describe("Branch identifier"),
|
|
64
|
-
needsMoreThoughts: z.boolean().optional().describe("If more thoughts are needed"),
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
selectedOption: z.string().optional().describe("The option selected")
|
|
87
|
+
branchId: z.string().optional().describe("Branch identifier (e.g., 'approach-b', 'alternative')"),
|
|
88
|
+
needsMoreThoughts: z.boolean().optional().describe("If more thoughts are needed beyond totalThoughts"),
|
|
89
|
+
score: z.number().min(1).max(10).optional().describe("Score for evaluation type (1-10)"),
|
|
90
|
+
options: z.array(z.string()).optional().describe("List of options for generation type"),
|
|
91
|
+
selectedOption: z.string().optional().describe("The option selected for selection type")
|
|
69
92
|
}, async (args) => {
|
|
70
93
|
const result = await thinkingServer.processThought(args);
|
|
71
94
|
return {
|
|
@@ -73,15 +96,15 @@ You MUST:
|
|
|
73
96
|
isError: result.isError
|
|
74
97
|
};
|
|
75
98
|
});
|
|
76
|
-
//
|
|
77
|
-
server.tool("clear_thought_history", "Clear the sequential thinking history.", {}, async () => {
|
|
99
|
+
// --- Clear Thought History ---
|
|
100
|
+
server.tool("clear_thought_history", "Clear the sequential thinking history. Use this to start fresh when changing to a completely different task.", {}, async () => {
|
|
78
101
|
await thinkingServer.clearHistory();
|
|
79
102
|
return {
|
|
80
|
-
content: [{ type: "text", text: "Thought history cleared." }]
|
|
103
|
+
content: [{ type: "text", text: "Thought history cleared. All blocks reset." }]
|
|
81
104
|
};
|
|
82
105
|
});
|
|
83
|
-
//
|
|
84
|
-
server.tool("summarize_history", "Compress multiple thoughts into a single summary thought to save space/context.", {
|
|
106
|
+
// --- Summarize History ---
|
|
107
|
+
server.tool("summarize_history", "Compress multiple thoughts into a single summary thought to save space/context. Useful for long-running tasks.", {
|
|
85
108
|
startIndex: z.number().int().min(1).describe("The starting thought number to summarize"),
|
|
86
109
|
endIndex: z.number().int().min(1).describe("The ending thought number to summarize"),
|
|
87
110
|
summary: z.string().describe("The summary text that replaces the range")
|
|
@@ -99,9 +122,9 @@ You MUST:
|
|
|
99
122
|
};
|
|
100
123
|
}
|
|
101
124
|
});
|
|
102
|
-
//
|
|
103
|
-
server.tool("search_thoughts", "Search through the thinking history to recall specific details or
|
|
104
|
-
query: z.string().describe("The search term or keyword to look for")
|
|
125
|
+
// --- Search Thoughts ---
|
|
126
|
+
server.tool("search_thoughts", "Search through the thinking history to recall specific details, past decisions, or tool results.", {
|
|
127
|
+
query: z.string().describe("The search term or keyword to look for (searches thought content, types, blocks, and tool calls)")
|
|
105
128
|
}, async ({ query }) => {
|
|
106
129
|
try {
|
|
107
130
|
const results = await thinkingServer.searchHistory(query);
|
|
@@ -121,4 +144,53 @@ You MUST:
|
|
|
121
144
|
};
|
|
122
145
|
}
|
|
123
146
|
});
|
|
147
|
+
// --- Start New Block ---
|
|
148
|
+
server.tool("start_thinking_block", "Explicitly start a new thinking block for a new topic/context. Use this when switching between distinct tasks to prevent false loop detection.", {
|
|
149
|
+
blockId: z.string().describe("Unique ID for the new block (e.g., 'debug-auth', 'implement-feature-x')"),
|
|
150
|
+
topic: z.string().describe("Short description of what this block is about")
|
|
151
|
+
}, async ({ blockId, topic }) => {
|
|
152
|
+
try {
|
|
153
|
+
thinkingServer.startNewBlock(blockId, topic);
|
|
154
|
+
return {
|
|
155
|
+
content: [{
|
|
156
|
+
type: "text",
|
|
157
|
+
text: `New thinking block started.\nBlock ID: ${blockId}\nTopic: ${topic}\n\nPrevious block has been archived. You can now think about "${topic}" without interference from previous context.`
|
|
158
|
+
}]
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
return {
|
|
163
|
+
content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
164
|
+
isError: true
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
// --- Get Blocks Summary ---
|
|
169
|
+
server.tool("get_thinking_blocks", "Get a summary of all thinking blocks to understand your thinking history across different topics.", {}, async () => {
|
|
170
|
+
try {
|
|
171
|
+
const blocks = thinkingServer.getBlocksSummary();
|
|
172
|
+
const currentBlock = thinkingServer.getCurrentBlock();
|
|
173
|
+
if (blocks.length === 0) {
|
|
174
|
+
return {
|
|
175
|
+
content: [{ type: "text", text: "No thinking blocks found. Start thinking to create your first block." }]
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
let output = `Thinking Blocks Summary (${blocks.length} blocks):\n\n`;
|
|
179
|
+
for (const block of blocks) {
|
|
180
|
+
const isCurrent = currentBlock && block.id === currentBlock.id;
|
|
181
|
+
output += `${isCurrent ? '>>> ' : ' '}[${block.status.toUpperCase()}] ${block.id}\n`;
|
|
182
|
+
output += ` Topic: ${block.topic}\n`;
|
|
183
|
+
output += ` Thoughts: ${block.thoughtCount}\n\n`;
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
content: [{ type: "text", text: output }]
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
return {
|
|
191
|
+
content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
192
|
+
isError: true
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
});
|
|
124
196
|
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare function execAsync(command: string, options?: {
|
|
2
|
+
timeout?: number;
|
|
3
|
+
maxBuffer?: number;
|
|
4
|
+
}): Promise<{
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare class AsyncMutex {
|
|
9
|
+
private mutex;
|
|
10
|
+
lock(): Promise<() => void>;
|
|
11
|
+
dispatch<T>(fn: (() => T | PromiseLike<T>)): Promise<T>;
|
|
12
|
+
}
|
|
13
|
+
export declare function validatePath(requestedPath: string): string;
|
|
14
|
+
export declare function validatePublicUrl(urlString: string): Promise<void>;
|
|
15
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
16
|
+
declare class Logger {
|
|
17
|
+
private level;
|
|
18
|
+
constructor();
|
|
19
|
+
private shouldLog;
|
|
20
|
+
debug(msg: string, ...args: any[]): void;
|
|
21
|
+
info(msg: string, ...args: any[]): void;
|
|
22
|
+
warn(msg: string, ...args: any[]): void;
|
|
23
|
+
error(msg: string, ...args: any[]): void;
|
|
24
|
+
}
|
|
25
|
+
export declare const logger: Logger;
|
|
26
|
+
export declare const DEFAULT_HEADERS: {
|
|
27
|
+
'User-Agent': string;
|
|
28
|
+
Accept: string;
|
|
29
|
+
'Accept-Language': string;
|
|
30
|
+
};
|
|
31
|
+
export declare function fetchWithRetry(url: string, options?: any, retries?: number, backoff?: number): Promise<Response>;
|
|
32
|
+
export {};
|