tracelattice 1.3.0 → 1.3.2
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 +2 -0
- package/dist/ServerConfig.d.ts +10 -11
- package/dist/ServerConfig.d.ts.map +1 -1
- package/dist/ServerConfig.js +7 -7
- package/dist/ServerConfig.js.map +1 -1
- package/dist/__tests__/core/retraction.test.d.ts +2 -0
- package/dist/__tests__/core/retraction.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/factories.d.ts +2 -0
- package/dist/__tests__/helpers/factories.d.ts.map +1 -1
- package/dist/cli.js +6 -6
- package/dist/core/HistoryManager.d.ts +45 -523
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +101 -249
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +17 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +110 -0
- package/dist/core/PersistenceBuffer.d.ts.map +1 -0
- package/dist/core/PersistenceBuffer.js +141 -0
- package/dist/core/PersistenceBuffer.js.map +1 -0
- package/dist/core/SessionManager.d.ts +58 -0
- package/dist/core/SessionManager.d.ts.map +1 -0
- package/dist/core/SessionManager.js +65 -0
- package/dist/core/SessionManager.js.map +1 -0
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +16 -4
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtFormatter.d.ts.map +1 -1
- package/dist/core/ThoughtFormatter.js +2 -1
- package/dist/core/ThoughtFormatter.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts +18 -0
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +47 -16
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/evaluator/Aggregator.d.ts.map +1 -1
- package/dist/core/evaluator/Aggregator.js +6 -2
- package/dist/core/evaluator/Aggregator.js.map +1 -1
- package/dist/core/evaluator/PatternDetector.js +2 -2
- package/dist/core/evaluator/PatternDetector.js.map +1 -1
- package/dist/core/evaluator/SignalComputer.d.ts +57 -5
- package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
- package/dist/core/evaluator/SignalComputer.js +52 -10
- package/dist/core/evaluator/SignalComputer.js.map +1 -1
- package/dist/core/graph/EdgeEmitter.d.ts +64 -0
- package/dist/core/graph/EdgeEmitter.d.ts.map +1 -0
- package/dist/core/graph/EdgeEmitter.js +99 -0
- package/dist/core/graph/EdgeEmitter.js.map +1 -0
- package/dist/core/reasoning.d.ts +17 -2
- package/dist/core/reasoning.d.ts.map +1 -1
- package/dist/core/thought.d.ts +7 -0
- package/dist/core/thought.d.ts.map +1 -1
- package/dist/core/tools/InMemorySuspensionStore.js +1 -1
- package/dist/core/tools/InMemorySuspensionStore.js.map +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +11 -0
- package/dist/lib.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +6 -0
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +8 -0
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +6 -0
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +3 -0
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceBackend.d.ts +6 -0
- package/dist/persistence/PersistenceBackend.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +6 -0
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +4 -0
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/schema.d.ts +3 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +8 -7
- package/dist/schema.js.map +1 -1
- package/package.json +2 -2
|
@@ -92,10 +92,18 @@ export declare class ThoughtProcessor {
|
|
|
92
92
|
* @private
|
|
93
93
|
*/
|
|
94
94
|
private log;
|
|
95
|
+
/**
|
|
96
|
+
* Priority ordering for warning patterns (lower = higher priority).
|
|
97
|
+
* Ensures the most actionable patterns fill the hint cap first.
|
|
98
|
+
*/
|
|
99
|
+
private static readonly _HINT_PRIORITY;
|
|
95
100
|
/**
|
|
96
101
|
* Generate actionable hints from pattern signals.
|
|
97
102
|
* Rules: max 3 hints, warning-severity only, cooldown of 3 thoughts per pattern per session.
|
|
98
103
|
*
|
|
104
|
+
* Warning patterns are sorted by priority before selection (see _HINT_PRIORITY).
|
|
105
|
+
* Higher-priority patterns (lower number) fill the hint cap first.
|
|
106
|
+
*
|
|
99
107
|
* @param patterns - Detected pattern signals
|
|
100
108
|
* @param currentThoughtNumber - The current thought number being processed
|
|
101
109
|
* @param sessionId - Session identifier for cooldown scoping
|
|
@@ -202,6 +210,16 @@ export declare class ThoughtProcessor {
|
|
|
202
210
|
* @private
|
|
203
211
|
*/
|
|
204
212
|
private _validateNewTypes;
|
|
213
|
+
/**
|
|
214
|
+
* Checks whether a given thought_number exists in the session history or any branch.
|
|
215
|
+
* @private
|
|
216
|
+
*/
|
|
217
|
+
private _thoughtNumberExists;
|
|
218
|
+
/**
|
|
219
|
+
* Returns a workaround thought type for a feature-flagged type.
|
|
220
|
+
* @private
|
|
221
|
+
*/
|
|
222
|
+
private static _getWorkaroundType;
|
|
205
223
|
/**
|
|
206
224
|
* Persist a tool_call thought and return a `suspended` envelope.
|
|
207
225
|
* Strategy/evaluator are intentionally skipped.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThoughtProcessor.d.ts","sourceRoot":"","sources":["../../src/core/ThoughtProcessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAE5D,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,4BAA4B,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,0BAA0B,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAUvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAoB9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAc;IAC9B,wEAAwE;IACxE,OAAO,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;IAEH,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,gBAAgB;IAwB3B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,gBAAgB;IAGxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS;IA9B3B,2CAA2C;IAC3C,OAAO,CAAC,OAAO,CAAS;IAExB,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAmB;IAErD;;;OAGG;IACH,OAAO,CAAC,cAAc,CAA0C;IAEhE;;;;;;;;;OASG;gBAEM,cAAc,EAAE,eAAe,EAC/B,gBAAgB,EAAE,gBAAgB,EAC1C,gBAAgB,EAAE,gBAAgB,EAClC,MAAM,CAAC,EAAE,MAAM,EACE,QAAQ,GAAE,kBAA6C,EACvD,mBAAmB,CAAC,EAAE,kBAAkB,YAAA,EACxC,gBAAgB,CAAC,EAAE,gBAAgB,YAAA,EACnC,SAAS,GAAE,YAA+B;IAM5D;;;;;OAKG;IACH,OAAO,CAAC,GAAG;IAIX
|
|
1
|
+
{"version":3,"file":"ThoughtProcessor.d.ts","sourceRoot":"","sources":["../../src/core/ThoughtProcessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAE5D,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,4BAA4B,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,0BAA0B,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAUvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAoB9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAc;IAC9B,wEAAwE;IACxE,OAAO,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;IAEH,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,gBAAgB;IAwB3B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,gBAAgB;IAGxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS;IA9B3B,2CAA2C;IAC3C,OAAO,CAAC,OAAO,CAAS;IAExB,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAmB;IAErD;;;OAGG;IACH,OAAO,CAAC,cAAc,CAA0C;IAEhE;;;;;;;;;OASG;gBAEM,cAAc,EAAE,eAAe,EAC/B,gBAAgB,EAAE,gBAAgB,EAC1C,gBAAgB,EAAE,gBAAgB,EAClC,MAAM,CAAC,EAAE,MAAM,EACE,QAAQ,GAAE,kBAA6C,EACvD,mBAAmB,CAAC,EAAE,kBAAkB,YAAA,EACxC,gBAAgB,CAAC,EAAE,gBAAgB,YAAA,EACnC,SAAS,GAAE,YAA+B;IAM5D;;;;;OAKG;IACH,OAAO,CAAC,GAAG;IAIX;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAKpC;IAEF;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAc;IAqCtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;IACU,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC;IAiIjE;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAiDpB;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAavB,oEAAoE;IACpE,OAAO,CAAC,aAAa;IAKrB;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,aAAa;IAoBrB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,wBAAwB;IAqGhC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAgDzB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAc5B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAWjC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAiCvB;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAY9B"}
|
|
@@ -4,13 +4,13 @@ import { GraphView } from "./graph/GraphView.js";
|
|
|
4
4
|
import { normalizeInput } from "./InputNormalizer.js";
|
|
5
5
|
import { SequentialStrategy } from "./reasoning/strategies/SequentialStrategy.js";
|
|
6
6
|
const DEFAULT_FEATURES = {
|
|
7
|
-
dagEdges:
|
|
7
|
+
dagEdges: true,
|
|
8
8
|
reasoningStrategy: 'sequential',
|
|
9
|
-
calibration:
|
|
10
|
-
compression:
|
|
11
|
-
toolInterleave:
|
|
12
|
-
newThoughtTypes:
|
|
13
|
-
outcomeRecording:
|
|
9
|
+
calibration: true,
|
|
10
|
+
compression: true,
|
|
11
|
+
toolInterleave: true,
|
|
12
|
+
newThoughtTypes: true,
|
|
13
|
+
outcomeRecording: true
|
|
14
14
|
};
|
|
15
15
|
class ThoughtProcessor {
|
|
16
16
|
historyManager;
|
|
@@ -35,9 +35,20 @@ class ThoughtProcessor {
|
|
|
35
35
|
log(message, meta) {
|
|
36
36
|
this._logger.info(message, meta);
|
|
37
37
|
}
|
|
38
|
+
static _HINT_PRIORITY = {
|
|
39
|
+
confidence_drift: 1,
|
|
40
|
+
unverified_hypothesis: 2,
|
|
41
|
+
no_alternatives_explored: 3,
|
|
42
|
+
consecutive_without_verification: 4
|
|
43
|
+
};
|
|
38
44
|
_generateHints(patterns, currentThoughtNumber, sessionId) {
|
|
39
45
|
const warnings = patterns.filter((p)=>'warning' === p.severity);
|
|
40
46
|
if (0 === warnings.length) return [];
|
|
47
|
+
warnings.sort((a, b)=>{
|
|
48
|
+
const pa = ThoughtProcessor._HINT_PRIORITY[a.pattern] ?? 99;
|
|
49
|
+
const pb = ThoughtProcessor._HINT_PRIORITY[b.pattern] ?? 99;
|
|
50
|
+
return pa - pb;
|
|
51
|
+
});
|
|
41
52
|
const sessionKey = sessionId ?? '__global__';
|
|
42
53
|
if (!this._hintCooldowns.has(sessionKey)) this._hintCooldowns.set(sessionKey, new Map());
|
|
43
54
|
const cooldowns = this._hintCooldowns.get(sessionKey);
|
|
@@ -70,7 +81,7 @@ class ThoughtProcessor {
|
|
|
70
81
|
...validateWarnings,
|
|
71
82
|
...refWarnings
|
|
72
83
|
];
|
|
73
|
-
this._validateNewTypes(checkedInput);
|
|
84
|
+
this._validateNewTypes(checkedInput, sessionId);
|
|
74
85
|
if ('tool_call' === checkedInput.thought_type && this._suspensionStore) return this._handleToolCall(checkedInput, sessionId);
|
|
75
86
|
if ('tool_observation' === checkedInput.thought_type && this._suspensionStore) this._handleToolObservation(checkedInput, sessionId);
|
|
76
87
|
this.historyManager.addThought(checkedInput);
|
|
@@ -113,7 +124,7 @@ class ThoughtProcessor {
|
|
|
113
124
|
strategy_hint: decision
|
|
114
125
|
},
|
|
115
126
|
...allWarnings.length > 0 && {
|
|
116
|
-
warnings: allWarnings
|
|
127
|
+
warnings: allWarnings.slice(0, 3)
|
|
117
128
|
},
|
|
118
129
|
...sessionId ? {
|
|
119
130
|
session_id: sessionId
|
|
@@ -205,7 +216,6 @@ class ThoughtProcessor {
|
|
|
205
216
|
_validateCrossReferences(input, sessionId) {
|
|
206
217
|
const warnings = [];
|
|
207
218
|
const historyLength = this.historyManager.getHistoryLength(sessionId);
|
|
208
|
-
const branchIds = new Set(this.historyManager.getBranchIds(sessionId));
|
|
209
219
|
if (void 0 !== input.verification_target && input.verification_target > historyLength) {
|
|
210
220
|
warnings.push(`Dropped dangling verification_target: ${input.verification_target} (history has ${historyLength} thoughts)`);
|
|
211
221
|
this._logger.warn('Dropped dangling verification_target', {
|
|
@@ -257,14 +267,14 @@ class ThoughtProcessor {
|
|
|
257
267
|
input.merge_from_thoughts = valid.length > 0 ? valid : void 0;
|
|
258
268
|
}
|
|
259
269
|
if (input.merge_branch_ids?.length) {
|
|
260
|
-
const valid = input.merge_branch_ids.filter((id)=>
|
|
270
|
+
const valid = input.merge_branch_ids.filter((id)=>this.historyManager.branchExists(sessionId, id));
|
|
261
271
|
if (valid.length < input.merge_branch_ids.length) {
|
|
262
|
-
const dropped = input.merge_branch_ids.filter((id)=>!
|
|
272
|
+
const dropped = input.merge_branch_ids.filter((id)=>!this.historyManager.branchExists(sessionId, id));
|
|
263
273
|
warnings.push(`Filtered dangling merge_branch_ids: [${dropped.join(', ')}]`);
|
|
264
274
|
this._logger.warn('Filtered dangling merge_branch_ids', {
|
|
265
275
|
original: input.merge_branch_ids,
|
|
266
276
|
filtered: valid,
|
|
267
|
-
existingBranches:
|
|
277
|
+
existingBranches: this.historyManager.getBranchIds(sessionId)
|
|
268
278
|
});
|
|
269
279
|
}
|
|
270
280
|
input.merge_branch_ids = valid.length > 0 ? valid : void 0;
|
|
@@ -274,13 +284,34 @@ class ThoughtProcessor {
|
|
|
274
284
|
warnings
|
|
275
285
|
};
|
|
276
286
|
}
|
|
277
|
-
_validateNewTypes(input) {
|
|
287
|
+
_validateNewTypes(input, sessionId) {
|
|
278
288
|
const t = input.thought_type;
|
|
279
|
-
if (('tool_call' === t || 'tool_observation' === t) && !this._features.toolInterleave) throw new ValidationError('thought_type',
|
|
280
|
-
if (('assumption' === t || 'decomposition' === t || 'backtrack' === t) && !this._features.newThoughtTypes) throw new ValidationError('thought_type',
|
|
289
|
+
if (('tool_call' === t || 'tool_observation' === t) && !this._features.toolInterleave) throw new ValidationError('thought_type', `Type '${t}' requires the toolInterleave feature flag. Set TRACELATTICE_FEATURES_TOOL_INTERLEAVE=true to enable it.`);
|
|
290
|
+
if (('assumption' === t || 'decomposition' === t || 'backtrack' === t) && !this._features.newThoughtTypes) throw new ValidationError('thought_type', `Type '${t}' requires the newThoughtTypes feature flag. Set TRACELATTICE_FEATURES_NEW_THOUGHT_TYPES=true to enable it, or use '${ThoughtProcessor._getWorkaroundType(t)}' type as a workaround.`);
|
|
281
291
|
if ('tool_call' === t && !input.tool_name) throw new InvalidToolCallError('tool_call thought ' + input.thought_number + ' missing required tool_name');
|
|
282
292
|
if ('tool_observation' === t && !input.continuation_token) throw new ValidationError('continuation_token', 'tool_observation thought ' + input.thought_number + ' missing continuation_token');
|
|
283
|
-
if ('backtrack' === t
|
|
293
|
+
if ('backtrack' === t) {
|
|
294
|
+
if (void 0 === input.backtrack_target) throw new ValidationError('backtrack_target', 'backtrack thought ' + input.thought_number + ' requires backtrack_target');
|
|
295
|
+
if (input.backtrack_target > input.thought_number) throw new InvalidBacktrackError('backtrack_target ' + input.backtrack_target + ' must be <= thought_number ' + input.thought_number);
|
|
296
|
+
if (!this._thoughtNumberExists(input.backtrack_target, sessionId)) throw new InvalidBacktrackError('backtrack_target ' + input.backtrack_target + ' does not exist in session history');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
_thoughtNumberExists(thoughtNumber, sessionId) {
|
|
300
|
+
const history = this.historyManager.getHistory(sessionId);
|
|
301
|
+
for (const t of history)if (t.thought_number === thoughtNumber) return true;
|
|
302
|
+
const branches = this.historyManager.getBranches(sessionId);
|
|
303
|
+
for (const branchThoughts of Object.values(branches))for (const t of branchThoughts)if (t.thought_number === thoughtNumber) return true;
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
static _getWorkaroundType(t) {
|
|
307
|
+
switch(t){
|
|
308
|
+
case 'assumption':
|
|
309
|
+
return 'regular';
|
|
310
|
+
case 'decomposition':
|
|
311
|
+
return 'hypothesis';
|
|
312
|
+
case 'backtrack':
|
|
313
|
+
return 'regular';
|
|
314
|
+
}
|
|
284
315
|
}
|
|
285
316
|
_handleToolCall(input, sessionId) {
|
|
286
317
|
this.historyManager.addThought(input);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/ThoughtProcessor.js","sources":["../../src/core/ThoughtProcessor.ts"],"sourcesContent":["/**\n * Core thought processing logic and validation.\n *\n * This module provides the `ThoughtProcessor` class which handles the main\n * sequential thinking request processing pipeline, including input validation,\n * history management, and response formatting.\n *\n * @module processor\n */\n\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { IEdgeStore } from '../contracts/interfaces.js';\nimport type { ISuspensionStore, SuspensionRecord } from '../contracts/suspension.js';\nimport type { IReasoningStrategy, StrategyDecision } from '../contracts/strategy.js';\nimport type { FeatureFlags } from '../ServerConfig.js';\nimport {\n\tInvalidBacktrackError,\n\tInvalidToolCallError,\n\tSuspensionExpiredError,\n\tSuspensionNotFoundError,\n\tValidationError,\n} from '../errors.js';\nimport { getErrorMessage } from '../errors.js';\nimport { GraphView } from './graph/GraphView.js';\nimport type { IHistoryManager } from './IHistoryManager.js';\nimport { normalizeInput } from './InputNormalizer.js';\nimport type { ThoughtData } from './thought.js';\nimport type { ThoughtEvaluator } from './ThoughtEvaluator.js';\nimport { ThoughtFormatter } from './ThoughtFormatter.js';\nimport type { PatternSignal } from './reasoning.js';\nimport { SequentialStrategy } from './reasoning/strategies/SequentialStrategy.js';\nimport type { CompressionService } from './compression/CompressionService.js';\n\n/**\n * Internal extension to ThoughtData carrying resume metadata.\n * Attached by `_handleToolObservation` so downstream consumers (e.g. edge\n * emission) can correlate the observation with the suspended `tool_call`.\n */\ntype ResumableThought = ThoughtData & { _resumedFrom?: number };\n\n/** Default feature flags used when none are supplied to ThoughtProcessor. */\nconst DEFAULT_FEATURES: FeatureFlags = {\n\tdagEdges: false,\n\treasoningStrategy: 'sequential',\n\tcalibration: false,\n\tcompression: false,\n\ttoolInterleave: false,\n\tnewThoughtTypes: false,\n\toutcomeRecording: false,\n};\n\n/**\n * The return type expected by MCP tool invocations.\n *\n * This structure matches the MCP protocol for tool results,\n * supporting both success and error responses.\n *\n * @example\n * ```typescript\n * const successResult: CallToolResult = {\n * content: [{ type: 'text', text: '{\"status\":\"success\"}' }]\n * };\n *\n * const errorResult: CallToolResult = {\n * content: [{ type: 'text', text: '{\"error\":\"Something went wrong\"}' }],\n * isError: true\n * };\n * ```\n */\nexport interface CallToolResult {\n\t/** Array of content blocks (typically text) to return to the client. */\n\tcontent: Array<{\n\t\ttype: 'text';\n\t\ttext: string;\n\t}>;\n\n\t/** Whether this result represents an error condition. */\n\tisError?: boolean;\n}\n\n/**\n * Core processor for sequential thinking requests.\n *\n * Pipeline: validate → normalize → add to history → format → evaluate signals\n * → run reasoning strategy → return structured response.\n *\n * Auto-adjusts `total_thoughts` if `thought_number` exceeds it. All errors are\n * caught and returned as formatted error responses with `isError: true`.\n *\n * @example\n * ```typescript\n * const processor = new ThoughtProcessor(historyManager, formatter, new ThoughtEvaluator());\n * const result = await processor.process({ thought: '...', thought_number: 1, total_thoughts: 5, next_thought_needed: true });\n * ```\n */\nexport class ThoughtProcessor {\n\t/** Logger for debugging and monitoring. */\n\tprivate _logger: Logger;\n\n\t/** Evaluator for quality signal computation. */\n\tprivate readonly _thoughtEvaluator: ThoughtEvaluator;\n\n\t/**\n\t * Per-session cooldown tracker: session_id → pattern → last_fired_thought_number.\n\t * Prevents re-firing the same pattern hint within 3 thoughts.\n\t */\n\tprivate _hintCooldowns = new Map<string, Map<string, number>>();\n\n\t/**\n\t * Creates a new ThoughtProcessor instance.\n\t *\n\t * @param historyManager - History manager for storing thoughts\n\t * @param thoughtFormatter - Formatter for output formatting\n\t * @param thoughtEvaluator - Evaluator for quality signal computation\n\t * @param logger - Optional logger for diagnostics (defaults to NullLogger)\n\t * @param strategy - Reasoning strategy controlling next-action decisions (defaults to SequentialStrategy)\n\t * @param compressionService - Optional compression service for auto-compression on terminate\n\t */\n\tconstructor(\n\t\tprivate historyManager: IHistoryManager,\n\t\tprivate thoughtFormatter: ThoughtFormatter,\n\t\tthoughtEvaluator: ThoughtEvaluator,\n\t\tlogger?: Logger,\n\t\tprivate readonly strategy: IReasoningStrategy = new SequentialStrategy(),\n\t\tprivate readonly _compressionService?: CompressionService,\n\t\tprivate readonly _suspensionStore?: ISuspensionStore,\n\t\tprivate readonly _features: FeatureFlags = DEFAULT_FEATURES\n\t) {\n\t\tthis._thoughtEvaluator = thoughtEvaluator;\n\t\tthis._logger = logger ?? new NullLogger();\n\t}\n\n\t/**\n\t * Internal logging method.\n\t * @param message - The message to log\n\t * @param meta - Optional metadata\n\t * @private\n\t */\n\tprivate log(message: string, meta?: Record<string, unknown>): void {\n\t\tthis._logger.info(message, meta);\n\t}\n\n\t/**\n\t * Generate actionable hints from pattern signals.\n\t * Rules: max 3 hints, warning-severity only, cooldown of 3 thoughts per pattern per session.\n\t *\n\t * @param patterns - Detected pattern signals\n\t * @param currentThoughtNumber - The current thought number being processed\n\t * @param sessionId - Session identifier for cooldown scoping\n\t * @returns Array of hint strings (max 3), empty if no warnings\n\t */\n\tprivate _generateHints(\n\t\tpatterns: PatternSignal[],\n\t\tcurrentThoughtNumber: number,\n\t\tsessionId?: string\n\t): string[] {\n\t\tconst warnings = patterns.filter((p) => p.severity === 'warning');\n\t\tif (warnings.length === 0) return [];\n\n\t\tconst sessionKey = sessionId ?? '__global__';\n\t\tif (!this._hintCooldowns.has(sessionKey)) {\n\t\t\tthis._hintCooldowns.set(sessionKey, new Map());\n\t\t}\n\t\tconst cooldowns = this._hintCooldowns.get(sessionKey)!;\n\n\t\tconst hints: string[] = [];\n\t\tfor (const warning of warnings) {\n\t\t\tif (hints.length >= 3) break;\n\n\t\t\tconst lastFired = cooldowns.get(warning.pattern);\n\t\t\tif (lastFired !== undefined && currentThoughtNumber - lastFired < 3) {\n\t\t\t\tcontinue; // Still in cooldown\n\t\t\t}\n\n\t\t\thints.push(warning.message);\n\t\t\tcooldowns.set(warning.pattern, currentThoughtNumber);\n\t\t}\n\n\t\treturn hints;\n\t}\n\n\t/**\n\t * Processes a thought through the sequential thinking pipeline.\n\t *\n\t * This method validates the input, adds it to history, formats the output,\n\t * computes quality signals via the ThoughtEvaluator, and returns\n\t * a structured response with metadata about the current state.\n\t *\n\t * @param input - The thought data to process\n\t * @returns A Promise resolving to the formatted tool result containing:\n\t * - `thought_number` — Current thought index\n\t * - `total_thoughts` — Estimated total thoughts\n\t * - `next_thought_needed` — Whether to continue\n\t * - `branches` — Active branch IDs\n\t * - `thought_history_length` — Number of thoughts in history\n\t * - `available_mcp_tools` — MCP tools available for recommendation\n\t * - `available_skills` — Skills available for recommendation\n\t * - `current_step` — Current step recommendation\n\t * - `previous_steps` — Previously recommended steps\n\t * - `remaining_steps` — Upcoming step descriptions\n\t * - `thought_type` — Classification of thought purpose (optional)\n\t * - `quality_score` — Self-assessed quality score 0-1 (optional)\n\t * - `confidence` — Self-assessed confidence 0-1 (optional)\n\t * - `hypothesis_id` — Hypothesis link for verification chains (optional)\n * - `confidence_signals` — Computed reasoning quality signals (includes structural_quality and quality_components)\n * - `reasoning_stats` — Aggregated reasoning analytics\n * - `reasoning_hints` — (Conditional) Actionable hints from pattern analysis, max 3, warning-severity only (optional)\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await processor.process({\n\t * thought: 'I should read the README file',\n\t * thought_number: 1,\n\t * total_thoughts: 3,\n\t * next_thought_needed: true\n\t * });\n\t *\n\t * console.log(result.content[0].text);\n\t * // Output includes: thought_number, total_thoughts, next_thought_needed,\n\t * // branches, thought_history_length, and any recommendations\n\t * ```\n\t */\n\tpublic async process(input: ThoughtData): Promise<CallToolResult> {\n\t\ttry {\n\t\t\t// Normalize input to handle common LLM field name mistakes\n\t\t\tconst normalizedInput = normalizeInput(input);\n\t\t\tconst sessionId = normalizedInput.session_id;\n\n\t\t\t// Handle reset_state: clear session before processing\n\t\t\tif (normalizedInput.reset_state) {\n\t\t\t\tthis.historyManager.clear(sessionId);\n\t\t\t\tthis.log('State reset for session', { sessionId: sessionId ?? '__global__' });\n\t\t\t}\n\n\t\t\t// Persist available_mcp_tools/available_skills across calls within a session.\n\t\t\t// If the caller omits these, reuse the last-seen values from the session.\n\t\t\tif (!normalizedInput.available_mcp_tools) {\n\t\t\t\tnormalizedInput.available_mcp_tools = this.historyManager.getAvailableMcpTools(sessionId);\n\t\t\t}\n\t\t\tif (!normalizedInput.available_skills) {\n\t\t\t\tnormalizedInput.available_skills = this.historyManager.getAvailableSkills(sessionId);\n\t\t\t}\n\n\t\t\tconst { result: validatedInput, warnings: validateWarnings } =\n\t\t\t\tthis.validateInput(normalizedInput);\n\t\t\tconst { result: checkedInput, warnings: refWarnings } =\n\t\t\t\tthis._validateCrossReferences(validatedInput, sessionId);\n\t\t\tconst allWarnings = [...validateWarnings, ...refWarnings];\n\n\t\t\t// Validate new thought types and tool-interleave invariants.\n\t\t\tthis._validateNewTypes(checkedInput);\n\n\t\t\t// Tool-interleave suspend path: persist the tool_call thought, then return\n\t\t\t// a `suspended` envelope without running strategy/evaluator.\n\t\t\tif (checkedInput.thought_type === 'tool_call' && this._suspensionStore) {\n\t\t\t\treturn this._handleToolCall(checkedInput, sessionId);\n\t\t\t}\n\n\t\t\t// Tool-interleave resume path: consume the suspension and continue the\n\t\t\t// normal pipeline (addThought → format → evaluate → strategy).\n\t\t\tif (checkedInput.thought_type === 'tool_observation' && this._suspensionStore) {\n\t\t\t\tthis._handleToolObservation(checkedInput, sessionId);\n\t\t\t}\n\n\t\t\tthis.historyManager.addThought(checkedInput);\n\n\t\t\tconst formattedThought = this.thoughtFormatter.formatThought(checkedInput);\n\t\t\tthis.log(formattedThought, { sessionId: sessionId ?? '__global__' });\n\n\t\t\t// Compute quality signals — fetch history/branches once\n\t\t\tconst history = this.historyManager.getHistory(sessionId);\n\t\t\tconst branches = this.historyManager.getBranches(sessionId);\n\n\t\t\tconst confidenceSignals = this._thoughtEvaluator.computeConfidenceSignals(\n\t\t\t\thistory,\n\t\t\t\tbranches\n\t\t\t);\n\t\t\tconst reasoningStats = this._thoughtEvaluator.computeReasoningStats(\n\t\t\t\thistory,\n\t\t\t\tbranches\n\t\t\t);\n\n\t\t\t// Detect reasoning patterns and generate hints\n\t\t\tconst patternSignals = this._thoughtEvaluator.computePatternSignals(\n\t\t\t\thistory,\n\t\t\t\tbranches\n\t\t\t);\n\t\t\tconst reasoningHints = this._generateHints(\n\t\t\t\tpatternSignals,\n\t\t\t\tcheckedInput.thought_number,\n\t\t\t\tsessionId\n\t\t\t);\n\n\t\t\t// Strategy decision — pluggable reasoning policy hook.\n\t\t\t// Built after history/stats so strategies see the latest state.\n\t\t\tconst decision = this._runStrategy(checkedInput, history, reasoningStats, sessionId);\n\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'text' as const,\n\t\t\t\t\t\ttext: JSON.stringify(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthought_number: checkedInput.thought_number,\n\t\t\t\t\t\t\ttotal_thoughts: checkedInput.total_thoughts,\n\t\t\t\t\t\t\tnext_thought_needed: checkedInput.next_thought_needed ?? true,\n\t\t\t\t\t\t\tbranches: this.historyManager.getBranchIds(sessionId),\n\t\t\t\t\t\t\tthought_history_length: this.historyManager.getHistoryLength(sessionId),\n\t\t\t\t\t\t\tavailable_mcp_tools: checkedInput.available_mcp_tools,\n\t\t\t\t\t\t\tavailable_skills: checkedInput.available_skills,\n\t\t\t\t\t\t\tcurrent_step: checkedInput.current_step,\n\t\t\t\t\t\t\tprevious_steps: checkedInput.previous_steps,\n\t\t\t\t\t\t\tremaining_steps: checkedInput.remaining_steps,\n\t\t\t\t\t\t\t// Reasoning enrichment fields\n\t\t\t\t\t\t\tthought_type: checkedInput.thought_type,\n\t\t\t\t\t\t\tquality_score: checkedInput.quality_score,\n\t\t\t\t\t\t\tconfidence: checkedInput.confidence,\n\t\t\t\t\t\t\thypothesis_id: checkedInput.hypothesis_id,\n\t\t\t\t\t\t\tconfidence_signals: confidenceSignals,\n\t\t\t\t\t\t\treasoning_stats: reasoningStats,\n\t\t\t\t\t\t\t...(reasoningHints.length > 0 && { reasoning_hints: reasoningHints }),\n\t\t\t\t\t\t\t...(decision.action !== 'continue' && { strategy_hint: decision }),\n\t\t\t\t\t\t\t...(allWarnings.length > 0 && { warnings: allWarnings }),\n\t\t\t\t\t\t\t...(sessionId ? { session_id: sessionId } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t2\n\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'text' as const,\n\t\t\t\t\t\ttext: JSON.stringify(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t\t\t\t\tstatus: 'failed',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t2\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Run the configured reasoning strategy and return its decision.\n\t * Strategy errors degrade to `{ action: 'continue' }`.\n\t * @private\n\t */\n\tprivate _runStrategy(\n\t\tcurrentThought: ThoughtData,\n\t\thistory: ThoughtData[],\n\t\tstats: ReturnType<ThoughtEvaluator['computeReasoningStats']>,\n\t\tsessionId?: string\n\t): StrategyDecision {\n\t\tlet decision: StrategyDecision;\n\t\ttry {\n\t\t\tconst edgeStore = this._getEdgeStore();\n\t\t\tconst graph = edgeStore ? new GraphView(edgeStore) : (undefined as unknown as GraphView);\n\t\t\tdecision = this.strategy.decide({\n\t\t\t\tsessionId: sessionId ?? '__global__',\n\t\t\t\thistory,\n\t\t\t\tgraph,\n\t\t\t\tstats,\n\t\t\t\tcurrentThought,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis._logger.warn('Reasoning strategy threw — defaulting to continue', {\n\t\t\t\tstrategy: this.strategy.name,\n\t\t\t\terror: getErrorMessage(error),\n\t\t\t});\n\t\t\tdecision = { action: 'continue' };\n\t\t}\n\n\t\t// Auto-compression trigger: when strategy terminates a branch and\n\t\t// compression is enabled, summarize the branch subtree. Compression\n\t\t// failures must NEVER break the thought pipeline.\n\t\tif (\n\t\t\tdecision.action === 'terminate' &&\n\t\t\tthis._compressionService &&\n\t\t\tcurrentThought.branch_id\n\t\t) {\n\t\t\ttry {\n\t\t\t\tconst sid = sessionId ?? '__global__';\n\t\t\t\tconst branchRoot = this._findBranchRoot(sid, currentThought.branch_id);\n\t\t\t\tif (branchRoot) {\n\t\t\t\t\tthis._compressionService.compressBranch(sid, currentThought.branch_id, branchRoot);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis._logger.debug('Compression auto-trigger failed', {\n\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn decision;\n\t}\n\n\t/**\n\t * Locate the root thought id for a branch.\n\t * Prefers GraphView.branchThoughts() when an EdgeStore is available;\n\t * falls back to historyManager.getBranches()[branchId][0].id.\n\t * @private\n\t */\n\tprivate _findBranchRoot(sessionId: string, branchId: string): string | undefined {\n\t\tconst edgeStore = this._getEdgeStore();\n\t\tconst branches = this.historyManager.getBranches(sessionId);\n\t\tconst branchList = branches[branchId];\n\t\tconst firstId = branchList?.[0]?.id;\n\t\tif (edgeStore && firstId) {\n\t\t\tconst graph = new GraphView(edgeStore);\n\t\t\tconst ids = graph.branchThoughts(sessionId, firstId);\n\t\t\tif (ids.length > 0) return ids[0];\n\t\t}\n\t\treturn firstId;\n\t}\n\n\t/** Best-effort access to the EdgeStore via duck typing. @private */\n\tprivate _getEdgeStore(): IEdgeStore | undefined {\n\t\tconst hm = this.historyManager as { getEdgeStore?: () => IEdgeStore | undefined };\n\t\treturn typeof hm.getEdgeStore === 'function' ? hm.getEdgeStore() : undefined;\n\t}\n\n\t/**\n\t * Validates and normalizes thought input.\n\t *\n\t * Ensures that thought numbers are consistent and within valid ranges.\n\t * If `thought_number` exceeds `total_thoughts`, `total_thoughts` is\n\t * automatically adjusted to match and a warning is emitted.\n\t *\n\t * @param input - The input to validate\n\t * @returns Object with validated input and any warnings generated\n\t * @private\n\t *\n\t * @example\n\t * ```typescript\n\t * // Auto-adjusts total_thoughts when thought_number exceeds it\n\t * const { result, warnings } = this.validateInput(input);\n\t * // result.total_thoughts === 10 (auto-adjusted from 5)\n\t * // warnings === ['Auto-adjusted total_thoughts from 5 to 10 to match thought_number']\n\t * ```\n\t */\n\tprivate validateInput(input: ThoughtData): {\n\t\tresult: ThoughtData;\n\t\twarnings: string[];\n\t} {\n\t\tconst warnings: string[] = [];\n\t\tif (input.thought_number > input.total_thoughts) {\n\t\t\tconst originalTotal = input.total_thoughts;\n\t\t\twarnings.push(\n\t\t\t\t`Auto-adjusted total_thoughts from ${originalTotal} to ${input.thought_number} to match thought_number`\n\t\t\t);\n\t\t\tthis._logger.warn('Auto-adjusted total_thoughts to match thought_number', {\n\t\t\t\tthought_number: input.thought_number,\n\t\t\t\toriginal_total_thoughts: originalTotal,\n\t\t\t\tadjusted_total_thoughts: input.thought_number,\n\t\t\t});\n\t\t\tinput.total_thoughts = input.thought_number;\n\t\t}\n\t\treturn { result: input, warnings };\n\t}\n\n\t/**\n\t * Validates cross-field references against actual thought history.\n\t * Drops invalid references with a warning log — never rejects.\n\t * LLMs frequently send optimistic references to thoughts that don't exist yet.\n\t *\n\t * @param input - The thought data to validate\n\t * @returns Object with cleaned input and any warnings generated\n\t * @private\n\t *\n\t * @example\n\t * ```typescript\n\t * // verification_target=999 with only 3 thoughts in history\n\t * const { result, warnings } = this._validateCrossReferences(input);\n\t * // result.verification_target === undefined\n\t * // warnings === ['Dropped dangling verification_target: 999 (history has 3 thoughts)']\n\t * ```\n\t */\n\tprivate _validateCrossReferences(input: ThoughtData, sessionId?: string): {\n\t\tresult: ThoughtData;\n\t\twarnings: string[];\n\t} {\n\t\tconst warnings: string[] = [];\n\t\tconst historyLength = this.historyManager.getHistoryLength(sessionId);\n\t\tconst branchIds = new Set(this.historyManager.getBranchIds(sessionId));\n\n\t\t// verification_target: must reference existing thought\n\t\tif (input.verification_target !== undefined && input.verification_target > historyLength) {\n\t\t\twarnings.push(\n\t\t\t\t`Dropped dangling verification_target: ${input.verification_target} (history has ${historyLength} thoughts)`\n\t\t\t);\n\t\t\tthis._logger.warn('Dropped dangling verification_target', {\n\t\t\t\tverification_target: input.verification_target,\n\t\t\t\thistoryLength,\n\t\t\t});\n\t\t\tinput.verification_target = undefined;\n\t\t}\n\n\t\t// revises_thought: must reference existing thought\n\t\tif (input.revises_thought !== undefined && input.revises_thought > historyLength) {\n\t\t\twarnings.push(\n\t\t\t\t`Dropped dangling revises_thought: ${input.revises_thought} (history has ${historyLength} thoughts)`\n\t\t\t);\n\t\t\tthis._logger.warn('Dropped dangling revises_thought', {\n\t\t\t\trevises_thought: input.revises_thought,\n\t\t\t\thistoryLength,\n\t\t\t});\n\t\t\tinput.revises_thought = undefined;\n\t\t}\n\n\t\t// branch_from_thought: must reference existing thought\n\t\tif (input.branch_from_thought !== undefined && input.branch_from_thought > historyLength) {\n\t\t\twarnings.push(\n\t\t\t\t`Dropped dangling branch_from_thought: ${input.branch_from_thought} (history has ${historyLength} thoughts)`\n\t\t\t);\n\t\t\tthis._logger.warn('Dropped dangling branch_from_thought', {\n\t\t\t\tbranch_from_thought: input.branch_from_thought,\n\t\t\t\thistoryLength,\n\t\t\t});\n\t\t\tinput.branch_from_thought = undefined;\n\t\t}\n\n\t\t// synthesis_sources: filter to existing thoughts only\n\t\tif (input.synthesis_sources?.length) {\n\t\t\tconst valid = input.synthesis_sources.filter((n: number) => n <= historyLength);\n\t\t\tif (valid.length < input.synthesis_sources.length) {\n\t\t\t\tconst dropped = input.synthesis_sources.filter((n: number) => n > historyLength);\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Filtered dangling synthesis_sources: [${dropped.join(', ')}] (history has ${historyLength} thoughts)`\n\t\t\t\t);\n\t\t\t\tthis._logger.warn('Filtered dangling synthesis_sources', {\n\t\t\t\t\toriginal: input.synthesis_sources,\n\t\t\t\t\tfiltered: valid,\n\t\t\t\t\thistoryLength,\n\t\t\t\t});\n\t\t\t}\n\t\t\tinput.synthesis_sources = valid.length > 0 ? valid : undefined;\n\t\t}\n\n\t\t// merge_from_thoughts: filter to existing thoughts only\n\t\tif (input.merge_from_thoughts?.length) {\n\t\t\tconst valid = input.merge_from_thoughts.filter((n: number) => n <= historyLength);\n\t\t\tif (valid.length < input.merge_from_thoughts.length) {\n\t\t\t\tconst dropped = input.merge_from_thoughts.filter(\n\t\t\t\t\t(n: number) => n > historyLength\n\t\t\t\t);\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Filtered dangling merge_from_thoughts: [${dropped.join(', ')}] (history has ${historyLength} thoughts)`\n\t\t\t\t);\n\t\t\t\tthis._logger.warn('Filtered dangling merge_from_thoughts', {\n\t\t\t\t\toriginal: input.merge_from_thoughts,\n\t\t\t\t\tfiltered: valid,\n\t\t\t\t\thistoryLength,\n\t\t\t\t});\n\t\t\t}\n\t\t\tinput.merge_from_thoughts = valid.length > 0 ? valid : undefined;\n\t\t}\n\n\t\t// merge_branch_ids: filter to existing branches only\n\t\tif (input.merge_branch_ids?.length) {\n\t\t\tconst valid = input.merge_branch_ids.filter((id: string) => branchIds.has(id));\n\t\t\tif (valid.length < input.merge_branch_ids.length) {\n\t\t\t\tconst dropped = input.merge_branch_ids.filter(\n\t\t\t\t\t(id: string) => !branchIds.has(id)\n\t\t\t\t);\n\t\t\t\twarnings.push(`Filtered dangling merge_branch_ids: [${dropped.join(', ')}]`);\n\t\t\t\tthis._logger.warn('Filtered dangling merge_branch_ids', {\n\t\t\t\t\toriginal: input.merge_branch_ids,\n\t\t\t\t\tfiltered: valid,\n\t\t\t\t\texistingBranches: Array.from(branchIds),\n\t\t\t\t});\n\t\t\t}\n\t\t\tinput.merge_branch_ids = valid.length > 0 ? valid : undefined;\n\t\t}\n\n\t\treturn { result: input, warnings };\n\t}\n\n\t/**\n\t * Validate new thought-type invariants behind feature flags.\n\t * @private\n\t */\n\tprivate _validateNewTypes(input: ThoughtData): void {\n\t\tconst t = input.thought_type;\n\t\tif ((t === 'tool_call' || t === 'tool_observation') && !this._features.toolInterleave) {\n\t\t\tthrow new ValidationError('thought_type', t + ' requires toolInterleave feature flag');\n\t\t}\n\t\tif (\n\t\t\t(t === 'assumption' || t === 'decomposition' || t === 'backtrack') &&\n\t\t\t!this._features.newThoughtTypes\n\t\t) {\n\t\t\tthrow new ValidationError('thought_type', t + ' requires newThoughtTypes feature flag');\n\t\t}\n\t\tif (t === 'tool_call' && !input.tool_name) {\n\t\t\tthrow new InvalidToolCallError(\n\t\t\t\t'tool_call thought ' + input.thought_number + ' missing required tool_name'\n\t\t\t);\n\t\t}\n\t\tif (t === 'tool_observation' && !input.continuation_token) {\n\t\t\tthrow new ValidationError(\n\t\t\t\t'continuation_token',\n\t\t\t\t'tool_observation thought ' + input.thought_number + ' missing continuation_token'\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tt === 'backtrack' &&\n\t\t\tinput.backtrack_target !== undefined &&\n\t\t\tinput.backtrack_target > input.thought_number\n\t\t) {\n\t\t\tthrow new InvalidBacktrackError(\n\t\t\t\t'backtrack_target ' + input.backtrack_target + ' must be <= thought_number ' + input.thought_number\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Persist a tool_call thought and return a `suspended` envelope.\n\t * Strategy/evaluator are intentionally skipped.\n\t * @private\n\t */\n\tprivate _handleToolCall(input: ThoughtData, sessionId?: string): CallToolResult {\n\t\tthis.historyManager.addThought(input);\n\t\tconst record: SuspensionRecord = this._suspensionStore!.suspend({\n\t\t\tsessionId: sessionId ?? '__global__',\n\t\t\ttoolCallThoughtNumber: input.thought_number,\n\t\t\ttoolName: input.tool_name!,\n\t\t\ttoolArguments: input.tool_arguments ?? {},\n\t\t\tttlMs: 5 * 60_000,\n\t\t\texpiresAt: 0,\n\t\t});\n\t\treturn {\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'text' as const,\n\t\t\t\t\ttext: JSON.stringify(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 'suspended',\n\t\t\t\t\t\t\tcontinuation_token: record.token,\n\t\t\t\t\t\t\ttool_name: record.toolName,\n\t\t\t\t\t\t\ttool_arguments: record.toolArguments,\n\t\t\t\t\t\t\texpires_at: record.expiresAt,\n\t\t\t\t\t\t\tthought_number: input.thought_number,\n\t\t\t\t\t\t\ttotal_thoughts: input.total_thoughts,\n\t\t\t\t\t\t\t...(sessionId ? { session_id: sessionId } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t2\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t}\n\n\t/**\n\t * Resume from a tool_observation, consuming the suspension record.\n\t * Distinguishes missing vs expired via peek().\n\t * @private\n\t */\n\tprivate _handleToolObservation(input: ThoughtData, _sessionId?: string): void {\n\t\tconst token = input.continuation_token!;\n\t\tconst peeked = this._suspensionStore!.peek(token);\n\t\tif (peeked && peeked.expiresAt <= Date.now()) {\n\t\t\tthrow new SuspensionExpiredError('Suspension token expired: ' + token);\n\t\t}\n\t\tconst record = this._suspensionStore!.resume(token);\n\t\tif (!record) {\n\t\t\tthrow new SuspensionNotFoundError('Suspension token not found: ' + token);\n\t\t}\n\t\t(input as ResumableThought)._resumedFrom = record.toolCallThoughtNumber;\n\t}\n}\n"],"names":["DEFAULT_FEATURES","ThoughtProcessor","Map","historyManager","thoughtFormatter","thoughtEvaluator","logger","strategy","SequentialStrategy","_compressionService","_suspensionStore","_features","NullLogger","message","meta","patterns","currentThoughtNumber","sessionId","warnings","p","sessionKey","cooldowns","hints","warning","lastFired","undefined","input","normalizedInput","normalizeInput","validatedInput","validateWarnings","checkedInput","refWarnings","allWarnings","formattedThought","history","branches","confidenceSignals","reasoningStats","patternSignals","reasoningHints","decision","JSON","error","getErrorMessage","currentThought","stats","edgeStore","graph","GraphView","sid","branchRoot","err","branchId","branchList","firstId","ids","hm","originalTotal","historyLength","branchIds","Set","valid","n","dropped","id","Array","t","ValidationError","InvalidToolCallError","InvalidBacktrackError","record","_sessionId","token","peeked","Date","SuspensionExpiredError","SuspensionNotFoundError"],"mappings":";;;;;AA0CA,MAAMA,mBAAiC;IACtC,UAAU;IACV,mBAAmB;IACnB,aAAa;IACb,aAAa;IACb,gBAAgB;IAChB,iBAAiB;IACjB,kBAAkB;AACnB;AA8CO,MAAMC;;;;;;;IAEJ,QAAgB;IAGP,kBAAoC;IAM7C,iBAAiB,IAAIC,MAAmC;IAYhE,YACSC,cAA+B,EAC/BC,gBAAkC,EAC1CC,gBAAkC,EAClCC,MAAe,EACEC,WAA+B,IAAIC,oBAAoB,EACvDC,mBAAwC,EACxCC,gBAAmC,EACnCC,YAA0BX,gBAAgB,CAC1D;aAROG,cAAc,GAAdA;aACAC,gBAAgB,GAAhBA;aAGSG,QAAQ,GAARA;aACAE,mBAAmB,GAAnBA;aACAC,gBAAgB,GAAhBA;aACAC,SAAS,GAATA;QAEjB,IAAI,CAAC,iBAAiB,GAAGN;QACzB,IAAI,CAAC,OAAO,GAAGC,UAAU,IAAIM;IAC9B;IAQQ,IAAIC,OAAe,EAAEC,IAA8B,EAAQ;QAClE,IAAI,CAAC,OAAO,CAAC,IAAI,CAACD,SAASC;IAC5B;IAWQ,eACPC,QAAyB,EACzBC,oBAA4B,EAC5BC,SAAkB,EACP;QACX,MAAMC,WAAWH,SAAS,MAAM,CAAC,CAACI,IAAMA,AAAe,cAAfA,EAAE,QAAQ;QAClD,IAAID,AAAoB,MAApBA,SAAS,MAAM,EAAQ,OAAO,EAAE;QAEpC,MAAME,aAAaH,aAAa;QAChC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAACG,aAC5B,IAAI,CAAC,cAAc,CAAC,GAAG,CAACA,YAAY,IAAIlB;QAEzC,MAAMmB,YAAY,IAAI,CAAC,cAAc,CAAC,GAAG,CAACD;QAE1C,MAAME,QAAkB,EAAE;QAC1B,KAAK,MAAMC,WAAWL,SAAU;YAC/B,IAAII,MAAM,MAAM,IAAI,GAAG;YAEvB,MAAME,YAAYH,UAAU,GAAG,CAACE,QAAQ,OAAO;YAC/C,IAAIC,AAAcC,WAAdD,cAA2BR,CAAAA,uBAAuBQ,YAAY;gBAIlEF,MAAM,IAAI,CAACC,QAAQ,OAAO;gBAC1BF,UAAU,GAAG,CAACE,QAAQ,OAAO,EAAEP;;QAChC;QAEA,OAAOM;IACR;IA2CA,MAAa,QAAQI,KAAkB,EAA2B;QACjE,IAAI;YAEH,MAAMC,kBAAkBC,eAAeF;YACvC,MAAMT,YAAYU,gBAAgB,UAAU;YAG5C,IAAIA,gBAAgB,WAAW,EAAE;gBAChC,IAAI,CAAC,cAAc,CAAC,KAAK,CAACV;gBAC1B,IAAI,CAAC,GAAG,CAAC,2BAA2B;oBAAE,WAAWA,aAAa;gBAAa;YAC5E;YAIA,IAAI,CAACU,gBAAgB,mBAAmB,EACvCA,gBAAgB,mBAAmB,GAAG,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAACV;YAEhF,IAAI,CAACU,gBAAgB,gBAAgB,EACpCA,gBAAgB,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,kBAAkB,CAACV;YAG3E,MAAM,EAAE,QAAQY,cAAc,EAAE,UAAUC,gBAAgB,EAAE,GAC3D,IAAI,CAAC,aAAa,CAACH;YACpB,MAAM,EAAE,QAAQI,YAAY,EAAE,UAAUC,WAAW,EAAE,GACpD,IAAI,CAAC,wBAAwB,CAACH,gBAAgBZ;YAC/C,MAAMgB,cAAc;mBAAIH;mBAAqBE;aAAY;YAGzD,IAAI,CAAC,iBAAiB,CAACD;YAIvB,IAAIA,AAA8B,gBAA9BA,aAAa,YAAY,IAAoB,IAAI,CAAC,gBAAgB,EACrE,OAAO,IAAI,CAAC,eAAe,CAACA,cAAcd;YAK3C,IAAIc,AAA8B,uBAA9BA,aAAa,YAAY,IAA2B,IAAI,CAAC,gBAAgB,EAC5E,IAAI,CAAC,sBAAsB,CAACA,cAAcd;YAG3C,IAAI,CAAC,cAAc,CAAC,UAAU,CAACc;YAE/B,MAAMG,mBAAmB,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAACH;YAC7D,IAAI,CAAC,GAAG,CAACG,kBAAkB;gBAAE,WAAWjB,aAAa;YAAa;YAGlE,MAAMkB,UAAU,IAAI,CAAC,cAAc,CAAC,UAAU,CAAClB;YAC/C,MAAMmB,WAAW,IAAI,CAAC,cAAc,CAAC,WAAW,CAACnB;YAEjD,MAAMoB,oBAAoB,IAAI,CAAC,iBAAiB,CAAC,wBAAwB,CACxEF,SACAC;YAED,MAAME,iBAAiB,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,CAClEH,SACAC;YAID,MAAMG,iBAAiB,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,CAClEJ,SACAC;YAED,MAAMI,iBAAiB,IAAI,CAAC,cAAc,CACzCD,gBACAR,aAAa,cAAc,EAC3Bd;YAKD,MAAMwB,WAAW,IAAI,CAAC,YAAY,CAACV,cAAcI,SAASG,gBAAgBrB;YAE1E,OAAO;gBACN,SAAS;oBACR;wBACC,MAAM;wBACN,MAAMyB,KAAK,SAAS,CACnB;4BACA,gBAAgBX,aAAa,cAAc;4BAC3C,gBAAgBA,aAAa,cAAc;4BAC3C,qBAAqBA,aAAa,mBAAmB,IAAI;4BACzD,UAAU,IAAI,CAAC,cAAc,CAAC,YAAY,CAACd;4BAC3C,wBAAwB,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAACA;4BAC7D,qBAAqBc,aAAa,mBAAmB;4BACrD,kBAAkBA,aAAa,gBAAgB;4BAC/C,cAAcA,aAAa,YAAY;4BACvC,gBAAgBA,aAAa,cAAc;4BAC3C,iBAAiBA,aAAa,eAAe;4BAE7C,cAAcA,aAAa,YAAY;4BACvC,eAAeA,aAAa,aAAa;4BACzC,YAAYA,aAAa,UAAU;4BACnC,eAAeA,aAAa,aAAa;4BACzC,oBAAoBM;4BACpB,iBAAiBC;4BACjB,GAAIE,eAAe,MAAM,GAAG,KAAK;gCAAE,iBAAiBA;4BAAe,CAAC;4BACpE,GAAIC,AAAoB,eAApBA,SAAS,MAAM,IAAmB;gCAAE,eAAeA;4BAAS,CAAC;4BACjE,GAAIR,YAAY,MAAM,GAAG,KAAK;gCAAE,UAAUA;4BAAY,CAAC;4BACvD,GAAIhB,YAAY;gCAAE,YAAYA;4BAAU,IAAI,CAAC,CAAC;wBAC/C,GACA,MACA;oBAED;iBACA;YACF;QACD,EAAE,OAAO0B,OAAO;YACf,OAAO;gBACN,SAAS;oBACR;wBACC,MAAM;wBACN,MAAMD,KAAK,SAAS,CACnB;4BACC,OAAOE,gBAAgBD;4BACvB,QAAQ;wBACT,GACA,MACA;oBAEF;iBACA;gBACD,SAAS;YACV;QACD;IACD;IAOQ,aACPE,cAA2B,EAC3BV,OAAsB,EACtBW,KAA4D,EAC5D7B,SAAkB,EACC;QACnB,IAAIwB;QACJ,IAAI;YACH,MAAMM,YAAY,IAAI,CAAC,aAAa;YACpC,MAAMC,QAAQD,YAAY,IAAIE,UAAUF,aAActB;YACtDgB,WAAW,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC/B,WAAWxB,aAAa;gBACxBkB;gBACAa;gBACAF;gBACAD;YACD;QACD,EAAE,OAAOF,OAAO;YACf,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,qDAAqD;gBACtE,UAAU,IAAI,CAAC,QAAQ,CAAC,IAAI;gBAC5B,OAAOC,gBAAgBD;YACxB;YACAF,WAAW;gBAAE,QAAQ;YAAW;QACjC;QAKA,IACCA,AAAoB,gBAApBA,SAAS,MAAM,IACf,IAAI,CAAC,mBAAmB,IACxBI,eAAe,SAAS,EAExB,IAAI;YACH,MAAMK,MAAMjC,aAAa;YACzB,MAAMkC,aAAa,IAAI,CAAC,eAAe,CAACD,KAAKL,eAAe,SAAS;YACrE,IAAIM,YACH,IAAI,CAAC,mBAAmB,CAAC,cAAc,CAACD,KAAKL,eAAe,SAAS,EAAEM;QAEzE,EAAE,OAAOC,KAAK;YACb,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,mCAAmC;gBACrD,OAAOR,gBAAgBQ;YACxB;QACD;QAGD,OAAOX;IACR;IAQQ,gBAAgBxB,SAAiB,EAAEoC,QAAgB,EAAsB;QAChF,MAAMN,YAAY,IAAI,CAAC,aAAa;QACpC,MAAMX,WAAW,IAAI,CAAC,cAAc,CAAC,WAAW,CAACnB;QACjD,MAAMqC,aAAalB,QAAQ,CAACiB,SAAS;QACrC,MAAME,UAAUD,YAAY,CAAC,EAAE,EAAE;QACjC,IAAIP,aAAaQ,SAAS;YACzB,MAAMP,QAAQ,IAAIC,UAAUF;YAC5B,MAAMS,MAAMR,MAAM,cAAc,CAAC/B,WAAWsC;YAC5C,IAAIC,IAAI,MAAM,GAAG,GAAG,OAAOA,GAAG,CAAC,EAAE;QAClC;QACA,OAAOD;IACR;IAGQ,gBAAwC;QAC/C,MAAME,KAAK,IAAI,CAAC,cAAc;QAC9B,OAAO,AAA2B,cAA3B,OAAOA,GAAG,YAAY,GAAkBA,GAAG,YAAY,KAAKhC;IACpE;IAqBQ,cAAcC,KAAkB,EAGtC;QACD,MAAMR,WAAqB,EAAE;QAC7B,IAAIQ,MAAM,cAAc,GAAGA,MAAM,cAAc,EAAE;YAChD,MAAMgC,gBAAgBhC,MAAM,cAAc;YAC1CR,SAAS,IAAI,CACZ,CAAC,kCAAkC,EAAEwC,cAAc,IAAI,EAAEhC,MAAM,cAAc,CAAC,wBAAwB,CAAC;YAExG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,wDAAwD;gBACzE,gBAAgBA,MAAM,cAAc;gBACpC,yBAAyBgC;gBACzB,yBAAyBhC,MAAM,cAAc;YAC9C;YACAA,MAAM,cAAc,GAAGA,MAAM,cAAc;QAC5C;QACA,OAAO;YAAE,QAAQA;YAAOR;QAAS;IAClC;IAmBQ,yBAAyBQ,KAAkB,EAAET,SAAkB,EAGrE;QACD,MAAMC,WAAqB,EAAE;QAC7B,MAAMyC,gBAAgB,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC1C;QAC3D,MAAM2C,YAAY,IAAIC,IAAI,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC5C;QAG3D,IAAIS,AAA8BD,WAA9BC,MAAM,mBAAmB,IAAkBA,MAAM,mBAAmB,GAAGiC,eAAe;YACzFzC,SAAS,IAAI,CACZ,CAAC,sCAAsC,EAAEQ,MAAM,mBAAmB,CAAC,cAAc,EAAEiC,cAAc,UAAU,CAAC;YAE7G,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,wCAAwC;gBACzD,qBAAqBjC,MAAM,mBAAmB;gBAC9CiC;YACD;YACAjC,MAAM,mBAAmB,GAAGD;QAC7B;QAGA,IAAIC,AAA0BD,WAA1BC,MAAM,eAAe,IAAkBA,MAAM,eAAe,GAAGiC,eAAe;YACjFzC,SAAS,IAAI,CACZ,CAAC,kCAAkC,EAAEQ,MAAM,eAAe,CAAC,cAAc,EAAEiC,cAAc,UAAU,CAAC;YAErG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,oCAAoC;gBACrD,iBAAiBjC,MAAM,eAAe;gBACtCiC;YACD;YACAjC,MAAM,eAAe,GAAGD;QACzB;QAGA,IAAIC,AAA8BD,WAA9BC,MAAM,mBAAmB,IAAkBA,MAAM,mBAAmB,GAAGiC,eAAe;YACzFzC,SAAS,IAAI,CACZ,CAAC,sCAAsC,EAAEQ,MAAM,mBAAmB,CAAC,cAAc,EAAEiC,cAAc,UAAU,CAAC;YAE7G,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,wCAAwC;gBACzD,qBAAqBjC,MAAM,mBAAmB;gBAC9CiC;YACD;YACAjC,MAAM,mBAAmB,GAAGD;QAC7B;QAGA,IAAIC,MAAM,iBAAiB,EAAE,QAAQ;YACpC,MAAMoC,QAAQpC,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAACqC,IAAcA,KAAKJ;YACjE,IAAIG,MAAM,MAAM,GAAGpC,MAAM,iBAAiB,CAAC,MAAM,EAAE;gBAClD,MAAMsC,UAAUtC,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAACqC,IAAcA,IAAIJ;gBAClEzC,SAAS,IAAI,CACZ,CAAC,sCAAsC,EAAE8C,QAAQ,IAAI,CAAC,MAAM,eAAe,EAAEL,cAAc,UAAU,CAAC;gBAEvG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,uCAAuC;oBACxD,UAAUjC,MAAM,iBAAiB;oBACjC,UAAUoC;oBACVH;gBACD;YACD;YACAjC,MAAM,iBAAiB,GAAGoC,MAAM,MAAM,GAAG,IAAIA,QAAQrC;QACtD;QAGA,IAAIC,MAAM,mBAAmB,EAAE,QAAQ;YACtC,MAAMoC,QAAQpC,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAACqC,IAAcA,KAAKJ;YACnE,IAAIG,MAAM,MAAM,GAAGpC,MAAM,mBAAmB,CAAC,MAAM,EAAE;gBACpD,MAAMsC,UAAUtC,MAAM,mBAAmB,CAAC,MAAM,CAC/C,CAACqC,IAAcA,IAAIJ;gBAEpBzC,SAAS,IAAI,CACZ,CAAC,wCAAwC,EAAE8C,QAAQ,IAAI,CAAC,MAAM,eAAe,EAAEL,cAAc,UAAU,CAAC;gBAEzG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,yCAAyC;oBAC1D,UAAUjC,MAAM,mBAAmB;oBACnC,UAAUoC;oBACVH;gBACD;YACD;YACAjC,MAAM,mBAAmB,GAAGoC,MAAM,MAAM,GAAG,IAAIA,QAAQrC;QACxD;QAGA,IAAIC,MAAM,gBAAgB,EAAE,QAAQ;YACnC,MAAMoC,QAAQpC,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAACuC,KAAeL,UAAU,GAAG,CAACK;YAC1E,IAAIH,MAAM,MAAM,GAAGpC,MAAM,gBAAgB,CAAC,MAAM,EAAE;gBACjD,MAAMsC,UAAUtC,MAAM,gBAAgB,CAAC,MAAM,CAC5C,CAACuC,KAAe,CAACL,UAAU,GAAG,CAACK;gBAEhC/C,SAAS,IAAI,CAAC,CAAC,qCAAqC,EAAE8C,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC3E,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,sCAAsC;oBACvD,UAAUtC,MAAM,gBAAgB;oBAChC,UAAUoC;oBACV,kBAAkBI,MAAM,IAAI,CAACN;gBAC9B;YACD;YACAlC,MAAM,gBAAgB,GAAGoC,MAAM,MAAM,GAAG,IAAIA,QAAQrC;QACrD;QAEA,OAAO;YAAE,QAAQC;YAAOR;QAAS;IAClC;IAMQ,kBAAkBQ,KAAkB,EAAQ;QACnD,MAAMyC,IAAIzC,MAAM,YAAY;QAC5B,IAAKyC,AAAAA,CAAAA,AAAM,gBAANA,KAAqBA,AAAM,uBAANA,CAAuB,KAAM,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,EACpF,MAAM,IAAIC,gBAAgB,gBAAgBD,IAAI;QAE/C,IACEA,AAAAA,CAAAA,AAAM,iBAANA,KAAsBA,AAAM,oBAANA,KAAyBA,AAAM,gBAANA,CAAgB,KAChE,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,EAE/B,MAAM,IAAIC,gBAAgB,gBAAgBD,IAAI;QAE/C,IAAIA,AAAM,gBAANA,KAAqB,CAACzC,MAAM,SAAS,EACxC,MAAM,IAAI2C,qBACT,uBAAuB3C,MAAM,cAAc,GAAG;QAGhD,IAAIyC,AAAM,uBAANA,KAA4B,CAACzC,MAAM,kBAAkB,EACxD,MAAM,IAAI0C,gBACT,sBACA,8BAA8B1C,MAAM,cAAc,GAAG;QAGvD,IACCyC,AAAM,gBAANA,KACAzC,AAA2BD,WAA3BC,MAAM,gBAAgB,IACtBA,MAAM,gBAAgB,GAAGA,MAAM,cAAc,EAE7C,MAAM,IAAI4C,sBACT,sBAAsB5C,MAAM,gBAAgB,GAAG,gCAAgCA,MAAM,cAAc;IAGtG;IAOQ,gBAAgBA,KAAkB,EAAET,SAAkB,EAAkB;QAC/E,IAAI,CAAC,cAAc,CAAC,UAAU,CAACS;QAC/B,MAAM6C,SAA2B,IAAI,CAAC,gBAAgB,CAAE,OAAO,CAAC;YAC/D,WAAWtD,aAAa;YACxB,uBAAuBS,MAAM,cAAc;YAC3C,UAAUA,MAAM,SAAS;YACzB,eAAeA,MAAM,cAAc,IAAI,CAAC;YACxC,OAAO;YACP,WAAW;QACZ;QACA,OAAO;YACN,SAAS;gBACR;oBACC,MAAM;oBACN,MAAMgB,KAAK,SAAS,CACnB;wBACC,QAAQ;wBACR,oBAAoB6B,OAAO,KAAK;wBAChC,WAAWA,OAAO,QAAQ;wBAC1B,gBAAgBA,OAAO,aAAa;wBACpC,YAAYA,OAAO,SAAS;wBAC5B,gBAAgB7C,MAAM,cAAc;wBACpC,gBAAgBA,MAAM,cAAc;wBACpC,GAAIT,YAAY;4BAAE,YAAYA;wBAAU,IAAI,CAAC,CAAC;oBAC/C,GACA,MACA;gBAEF;aACA;QACF;IACD;IAOQ,uBAAuBS,KAAkB,EAAE8C,UAAmB,EAAQ;QAC7E,MAAMC,QAAQ/C,MAAM,kBAAkB;QACtC,MAAMgD,SAAS,IAAI,CAAC,gBAAgB,CAAE,IAAI,CAACD;QAC3C,IAAIC,UAAUA,OAAO,SAAS,IAAIC,KAAK,GAAG,IACzC,MAAM,IAAIC,uBAAuB,+BAA+BH;QAEjE,MAAMF,SAAS,IAAI,CAAC,gBAAgB,CAAE,MAAM,CAACE;QAC7C,IAAI,CAACF,QACJ,MAAM,IAAIM,wBAAwB,iCAAiCJ;QAEnE/C,MAA2B,YAAY,GAAG6C,OAAO,qBAAqB;IACxE;AACD"}
|
|
1
|
+
{"version":3,"file":"core/ThoughtProcessor.js","sources":["../../src/core/ThoughtProcessor.ts"],"sourcesContent":["/**\n * Core thought processing logic and validation.\n *\n * This module provides the `ThoughtProcessor` class which handles the main\n * sequential thinking request processing pipeline, including input validation,\n * history management, and response formatting.\n *\n * @module processor\n */\n\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { IEdgeStore } from '../contracts/interfaces.js';\nimport type { ISuspensionStore, SuspensionRecord } from '../contracts/suspension.js';\nimport type { IReasoningStrategy, StrategyDecision } from '../contracts/strategy.js';\nimport type { FeatureFlags } from '../ServerConfig.js';\nimport {\n\tInvalidBacktrackError,\n\tInvalidToolCallError,\n\tSuspensionExpiredError,\n\tSuspensionNotFoundError,\n\tValidationError,\n} from '../errors.js';\nimport { getErrorMessage } from '../errors.js';\nimport { GraphView } from './graph/GraphView.js';\nimport type { IHistoryManager } from './IHistoryManager.js';\nimport { normalizeInput } from './InputNormalizer.js';\nimport type { ThoughtData } from './thought.js';\nimport type { ThoughtEvaluator } from './ThoughtEvaluator.js';\nimport { ThoughtFormatter } from './ThoughtFormatter.js';\nimport type { PatternSignal } from './reasoning.js';\nimport { SequentialStrategy } from './reasoning/strategies/SequentialStrategy.js';\nimport type { CompressionService } from './compression/CompressionService.js';\n\n/**\n * Internal extension to ThoughtData carrying resume metadata.\n * Attached by `_handleToolObservation` so downstream consumers (e.g. edge\n * emission) can correlate the observation with the suspended `tool_call`.\n */\ntype ResumableThought = ThoughtData & { _resumedFrom?: number };\n\n/** Default feature flags used when none are supplied to ThoughtProcessor. */\nconst DEFAULT_FEATURES: FeatureFlags = {\n\tdagEdges: true,\n\treasoningStrategy: 'sequential',\n\tcalibration: true,\n\tcompression: true,\n\ttoolInterleave: true,\n\tnewThoughtTypes: true,\n\toutcomeRecording: true,\n};\n\n/**\n * The return type expected by MCP tool invocations.\n *\n * This structure matches the MCP protocol for tool results,\n * supporting both success and error responses.\n *\n * @example\n * ```typescript\n * const successResult: CallToolResult = {\n * content: [{ type: 'text', text: '{\"status\":\"success\"}' }]\n * };\n *\n * const errorResult: CallToolResult = {\n * content: [{ type: 'text', text: '{\"error\":\"Something went wrong\"}' }],\n * isError: true\n * };\n * ```\n */\nexport interface CallToolResult {\n\t/** Array of content blocks (typically text) to return to the client. */\n\tcontent: Array<{\n\t\ttype: 'text';\n\t\ttext: string;\n\t}>;\n\n\t/** Whether this result represents an error condition. */\n\tisError?: boolean;\n}\n\n/**\n * Core processor for sequential thinking requests.\n *\n * Pipeline: validate → normalize → add to history → format → evaluate signals\n * → run reasoning strategy → return structured response.\n *\n * Auto-adjusts `total_thoughts` if `thought_number` exceeds it. All errors are\n * caught and returned as formatted error responses with `isError: true`.\n *\n * @example\n * ```typescript\n * const processor = new ThoughtProcessor(historyManager, formatter, new ThoughtEvaluator());\n * const result = await processor.process({ thought: '...', thought_number: 1, total_thoughts: 5, next_thought_needed: true });\n * ```\n */\nexport class ThoughtProcessor {\n\t/** Logger for debugging and monitoring. */\n\tprivate _logger: Logger;\n\n\t/** Evaluator for quality signal computation. */\n\tprivate readonly _thoughtEvaluator: ThoughtEvaluator;\n\n\t/**\n\t * Per-session cooldown tracker: session_id → pattern → last_fired_thought_number.\n\t * Prevents re-firing the same pattern hint within 3 thoughts.\n\t */\n\tprivate _hintCooldowns = new Map<string, Map<string, number>>();\n\n\t/**\n\t * Creates a new ThoughtProcessor instance.\n\t *\n\t * @param historyManager - History manager for storing thoughts\n\t * @param thoughtFormatter - Formatter for output formatting\n\t * @param thoughtEvaluator - Evaluator for quality signal computation\n\t * @param logger - Optional logger for diagnostics (defaults to NullLogger)\n\t * @param strategy - Reasoning strategy controlling next-action decisions (defaults to SequentialStrategy)\n\t * @param compressionService - Optional compression service for auto-compression on terminate\n\t */\n\tconstructor(\n\t\tprivate historyManager: IHistoryManager,\n\t\tprivate thoughtFormatter: ThoughtFormatter,\n\t\tthoughtEvaluator: ThoughtEvaluator,\n\t\tlogger?: Logger,\n\t\tprivate readonly strategy: IReasoningStrategy = new SequentialStrategy(),\n\t\tprivate readonly _compressionService?: CompressionService,\n\t\tprivate readonly _suspensionStore?: ISuspensionStore,\n\t\tprivate readonly _features: FeatureFlags = DEFAULT_FEATURES\n\t) {\n\t\tthis._thoughtEvaluator = thoughtEvaluator;\n\t\tthis._logger = logger ?? new NullLogger();\n\t}\n\n\t/**\n\t * Internal logging method.\n\t * @param message - The message to log\n\t * @param meta - Optional metadata\n\t * @private\n\t */\n\tprivate log(message: string, meta?: Record<string, unknown>): void {\n\t\tthis._logger.info(message, meta);\n\t}\n\n\t/**\n\t * Priority ordering for warning patterns (lower = higher priority).\n\t * Ensures the most actionable patterns fill the hint cap first.\n\t */\n\tprivate static readonly _HINT_PRIORITY: Readonly<Record<string, number>> = {\n\t\tconfidence_drift: 1, // Most actionable — degrading confidence\n\t\tunverified_hypothesis: 2, // Important for quality\n\t\tno_alternatives_explored: 3, // Breadth gap\n\t\tconsecutive_without_verification: 4, // Routine pattern\n\t};\n\n\t/**\n\t * Generate actionable hints from pattern signals.\n\t * Rules: max 3 hints, warning-severity only, cooldown of 3 thoughts per pattern per session.\n\t *\n\t * Warning patterns are sorted by priority before selection (see _HINT_PRIORITY).\n\t * Higher-priority patterns (lower number) fill the hint cap first.\n\t *\n\t * @param patterns - Detected pattern signals\n\t * @param currentThoughtNumber - The current thought number being processed\n\t * @param sessionId - Session identifier for cooldown scoping\n\t * @returns Array of hint strings (max 3), empty if no warnings\n\t */\n\tprivate _generateHints(\n\t\tpatterns: PatternSignal[],\n\t\tcurrentThoughtNumber: number,\n\t\tsessionId?: string\n\t): string[] {\n\t\tconst warnings = patterns.filter((p) => p.severity === 'warning');\n\t\tif (warnings.length === 0) return [];\n\n\t\t// Sort by priority (lower number = higher priority)\n\t\twarnings.sort((a, b) => {\n\t\t\tconst pa = ThoughtProcessor._HINT_PRIORITY[a.pattern] ?? 99;\n\t\t\tconst pb = ThoughtProcessor._HINT_PRIORITY[b.pattern] ?? 99;\n\t\t\treturn pa - pb;\n\t\t});\n\n\t\tconst sessionKey = sessionId ?? '__global__';\n\t\tif (!this._hintCooldowns.has(sessionKey)) {\n\t\t\tthis._hintCooldowns.set(sessionKey, new Map());\n\t\t}\n\t\tconst cooldowns = this._hintCooldowns.get(sessionKey)!;\n\n\t\tconst hints: string[] = [];\n\t\tfor (const warning of warnings) {\n\t\t\tif (hints.length >= 3) break;\n\n\t\t\tconst lastFired = cooldowns.get(warning.pattern);\n\t\t\tif (lastFired !== undefined && currentThoughtNumber - lastFired < 3) {\n\t\t\t\tcontinue; // Still in cooldown\n\t\t\t}\n\n\t\t\thints.push(warning.message);\n\t\t\tcooldowns.set(warning.pattern, currentThoughtNumber);\n\t\t}\n\n\t\treturn hints;\n\t}\n\n\t/**\n\t * Processes a thought through the sequential thinking pipeline.\n\t *\n\t * This method validates the input, adds it to history, formats the output,\n\t * computes quality signals via the ThoughtEvaluator, and returns\n\t * a structured response with metadata about the current state.\n\t *\n\t * @param input - The thought data to process\n\t * @returns A Promise resolving to the formatted tool result containing:\n\t * - `thought_number` — Current thought index\n\t * - `total_thoughts` — Estimated total thoughts\n\t * - `next_thought_needed` — Whether to continue\n\t * - `branches` — Active branch IDs\n\t * - `thought_history_length` — Number of thoughts in history\n\t * - `available_mcp_tools` — MCP tools available for recommendation\n\t * - `available_skills` — Skills available for recommendation\n\t * - `current_step` — Current step recommendation\n\t * - `previous_steps` — Previously recommended steps\n\t * - `remaining_steps` — Upcoming step descriptions\n\t * - `thought_type` — Classification of thought purpose (optional)\n\t * - `quality_score` — Self-assessed quality score 0-1 (optional)\n\t * - `confidence` — Self-assessed confidence 0-1 (optional)\n\t * - `hypothesis_id` — Hypothesis link for verification chains (optional)\n * - `confidence_signals` — Computed reasoning quality signals (includes structural_quality and quality_components)\n * - `reasoning_stats` — Aggregated reasoning analytics\n * - `reasoning_hints` — (Conditional) Actionable hints from pattern analysis, max 3, warning-severity only (optional)\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await processor.process({\n\t * thought: 'I should read the README file',\n\t * thought_number: 1,\n\t * total_thoughts: 3,\n\t * next_thought_needed: true\n\t * });\n\t *\n\t * console.log(result.content[0].text);\n\t * // Output includes: thought_number, total_thoughts, next_thought_needed,\n\t * // branches, thought_history_length, and any recommendations\n\t * ```\n\t */\n\tpublic async process(input: ThoughtData): Promise<CallToolResult> {\n\t\ttry {\n\t\t\t// Normalize input to handle common LLM field name mistakes\n\t\t\tconst normalizedInput = normalizeInput(input);\n\t\t\tconst sessionId = normalizedInput.session_id;\n\n\t\t\t// Handle reset_state: clear session before processing\n\t\t\tif (normalizedInput.reset_state) {\n\t\t\t\tthis.historyManager.clear(sessionId);\n\t\t\t\tthis.log('State reset for session', { sessionId: sessionId ?? '__global__' });\n\t\t\t}\n\n\t\t\t// Persist available_mcp_tools/available_skills across calls within a session.\n\t\t\t// If the caller omits these, reuse the last-seen values from the session.\n\t\t\tif (!normalizedInput.available_mcp_tools) {\n\t\t\t\tnormalizedInput.available_mcp_tools = this.historyManager.getAvailableMcpTools(sessionId);\n\t\t\t}\n\t\t\tif (!normalizedInput.available_skills) {\n\t\t\t\tnormalizedInput.available_skills = this.historyManager.getAvailableSkills(sessionId);\n\t\t\t}\n\n\t\t\tconst { result: validatedInput, warnings: validateWarnings } =\n\t\t\t\tthis.validateInput(normalizedInput);\n\t\t\tconst { result: checkedInput, warnings: refWarnings } =\n\t\t\t\tthis._validateCrossReferences(validatedInput, sessionId);\n\t\t\tconst allWarnings = [...validateWarnings, ...refWarnings];\n\n\t\t\t// Validate new thought types and tool-interleave invariants.\n\t\t\tthis._validateNewTypes(checkedInput, sessionId);\n\n\t\t\t// Tool-interleave suspend path: persist the tool_call thought, then return\n\t\t\t// a `suspended` envelope without running strategy/evaluator.\n\t\t\tif (checkedInput.thought_type === 'tool_call' && this._suspensionStore) {\n\t\t\t\treturn this._handleToolCall(checkedInput, sessionId);\n\t\t\t}\n\n\t\t\t// Tool-interleave resume path: consume the suspension and continue the\n\t\t\t// normal pipeline (addThought → format → evaluate → strategy).\n\t\t\tif (checkedInput.thought_type === 'tool_observation' && this._suspensionStore) {\n\t\t\t\tthis._handleToolObservation(checkedInput, sessionId);\n\t\t\t}\n\n\t\t\tthis.historyManager.addThought(checkedInput);\n\n\t\t\tconst formattedThought = this.thoughtFormatter.formatThought(checkedInput);\n\t\t\tthis.log(formattedThought, { sessionId: sessionId ?? '__global__' });\n\n\t\t\t// Compute quality signals — fetch history/branches once\n\t\t\tconst history = this.historyManager.getHistory(sessionId);\n\t\t\tconst branches = this.historyManager.getBranches(sessionId);\n\n\t\t\tconst confidenceSignals = this._thoughtEvaluator.computeConfidenceSignals(\n\t\t\t\thistory,\n\t\t\t\tbranches\n\t\t\t);\n\t\t\tconst reasoningStats = this._thoughtEvaluator.computeReasoningStats(\n\t\t\t\thistory,\n\t\t\t\tbranches\n\t\t\t);\n\n\t\t\t// Detect reasoning patterns and generate hints\n\t\t\tconst patternSignals = this._thoughtEvaluator.computePatternSignals(\n\t\t\t\thistory,\n\t\t\t\tbranches\n\t\t\t);\n\t\t\tconst reasoningHints = this._generateHints(\n\t\t\t\tpatternSignals,\n\t\t\t\tcheckedInput.thought_number,\n\t\t\t\tsessionId\n\t\t\t);\n\n\t\t\t// Strategy decision — pluggable reasoning policy hook.\n\t\t\t// Built after history/stats so strategies see the latest state.\n\t\t\tconst decision = this._runStrategy(checkedInput, history, reasoningStats, sessionId);\n\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'text' as const,\n\t\t\t\t\t\ttext: JSON.stringify(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthought_number: checkedInput.thought_number,\n\t\t\t\t\t\t\ttotal_thoughts: checkedInput.total_thoughts,\n\t\t\t\t\t\t\tnext_thought_needed: checkedInput.next_thought_needed ?? true,\n\t\t\t\t\t\t\tbranches: this.historyManager.getBranchIds(sessionId),\n\t\t\t\t\t\t\tthought_history_length: this.historyManager.getHistoryLength(sessionId),\n\t\t\t\t\t\t\tavailable_mcp_tools: checkedInput.available_mcp_tools,\n\t\t\t\t\t\t\tavailable_skills: checkedInput.available_skills,\n\t\t\t\t\t\t\tcurrent_step: checkedInput.current_step,\n\t\t\t\t\t\t\tprevious_steps: checkedInput.previous_steps,\n\t\t\t\t\t\t\tremaining_steps: checkedInput.remaining_steps,\n\t\t\t\t\t\t\t// Reasoning enrichment fields\n\t\t\t\t\t\t\tthought_type: checkedInput.thought_type,\n\t\t\t\t\t\t\tquality_score: checkedInput.quality_score,\n\t\t\t\t\t\t\tconfidence: checkedInput.confidence,\n\t\t\t\t\t\t\thypothesis_id: checkedInput.hypothesis_id,\n\t\t\t\t\t\t\tconfidence_signals: confidenceSignals,\n\t\t\t\t\t\t\treasoning_stats: reasoningStats,\n\t\t\t\t\t\t\t...(reasoningHints.length > 0 && { reasoning_hints: reasoningHints }),\n\t\t\t\t\t\t\t...(decision.action !== 'continue' && { strategy_hint: decision }),\n\t\t\t\t\t\t\t...(allWarnings.length > 0 && { warnings: allWarnings.slice(0, 3) }),\n\t\t\t\t\t\t\t...(sessionId ? { session_id: sessionId } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t2\n\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'text' as const,\n\t\t\t\t\t\ttext: JSON.stringify(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t\t\t\t\tstatus: 'failed',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t2\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Run the configured reasoning strategy and return its decision.\n\t * Strategy errors degrade to `{ action: 'continue' }`.\n\t * @private\n\t */\n\tprivate _runStrategy(\n\t\tcurrentThought: ThoughtData,\n\t\thistory: ThoughtData[],\n\t\tstats: ReturnType<ThoughtEvaluator['computeReasoningStats']>,\n\t\tsessionId?: string\n\t): StrategyDecision {\n\t\tlet decision: StrategyDecision;\n\t\ttry {\n\t\t\tconst edgeStore = this._getEdgeStore();\n\t\t\tconst graph = edgeStore ? new GraphView(edgeStore) : (undefined as unknown as GraphView);\n\t\t\tdecision = this.strategy.decide({\n\t\t\t\tsessionId: sessionId ?? '__global__',\n\t\t\t\thistory,\n\t\t\t\tgraph,\n\t\t\t\tstats,\n\t\t\t\tcurrentThought,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis._logger.warn('Reasoning strategy threw — defaulting to continue', {\n\t\t\t\tstrategy: this.strategy.name,\n\t\t\t\terror: getErrorMessage(error),\n\t\t\t});\n\t\t\tdecision = { action: 'continue' };\n\t\t}\n\n\t\t// Auto-compression trigger: when strategy terminates a branch and\n\t\t// compression is enabled, summarize the branch subtree. Compression\n\t\t// failures must NEVER break the thought pipeline.\n\t\tif (\n\t\t\tdecision.action === 'terminate' &&\n\t\t\tthis._compressionService &&\n\t\t\tcurrentThought.branch_id\n\t\t) {\n\t\t\ttry {\n\t\t\t\tconst sid = sessionId ?? '__global__';\n\t\t\t\tconst branchRoot = this._findBranchRoot(sid, currentThought.branch_id);\n\t\t\t\tif (branchRoot) {\n\t\t\t\t\tthis._compressionService.compressBranch(sid, currentThought.branch_id, branchRoot);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis._logger.debug('Compression auto-trigger failed', {\n\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn decision;\n\t}\n\n\t/**\n\t * Locate the root thought id for a branch.\n\t * Prefers GraphView.branchThoughts() when an EdgeStore is available;\n\t * falls back to historyManager.getBranches()[branchId][0].id.\n\t * @private\n\t */\n\tprivate _findBranchRoot(sessionId: string, branchId: string): string | undefined {\n\t\tconst edgeStore = this._getEdgeStore();\n\t\tconst branches = this.historyManager.getBranches(sessionId);\n\t\tconst branchList = branches[branchId];\n\t\tconst firstId = branchList?.[0]?.id;\n\t\tif (edgeStore && firstId) {\n\t\t\tconst graph = new GraphView(edgeStore);\n\t\t\tconst ids = graph.branchThoughts(sessionId, firstId);\n\t\t\tif (ids.length > 0) return ids[0];\n\t\t}\n\t\treturn firstId;\n\t}\n\n\t/** Best-effort access to the EdgeStore via duck typing. @private */\n\tprivate _getEdgeStore(): IEdgeStore | undefined {\n\t\tconst hm = this.historyManager as { getEdgeStore?: () => IEdgeStore | undefined };\n\t\treturn typeof hm.getEdgeStore === 'function' ? hm.getEdgeStore() : undefined;\n\t}\n\n\t/**\n\t * Validates and normalizes thought input.\n\t *\n\t * Ensures that thought numbers are consistent and within valid ranges.\n\t * If `thought_number` exceeds `total_thoughts`, `total_thoughts` is\n\t * automatically adjusted to match and a warning is emitted.\n\t *\n\t * @param input - The input to validate\n\t * @returns Object with validated input and any warnings generated\n\t * @private\n\t *\n\t * @example\n\t * ```typescript\n\t * // Auto-adjusts total_thoughts when thought_number exceeds it\n\t * const { result, warnings } = this.validateInput(input);\n\t * // result.total_thoughts === 10 (auto-adjusted from 5)\n\t * // warnings === ['Auto-adjusted total_thoughts from 5 to 10 to match thought_number']\n\t * ```\n\t */\n\tprivate validateInput(input: ThoughtData): {\n\t\tresult: ThoughtData;\n\t\twarnings: string[];\n\t} {\n\t\tconst warnings: string[] = [];\n\t\tif (input.thought_number > input.total_thoughts) {\n\t\t\tconst originalTotal = input.total_thoughts;\n\t\t\twarnings.push(\n\t\t\t\t`Auto-adjusted total_thoughts from ${originalTotal} to ${input.thought_number} to match thought_number`\n\t\t\t);\n\t\t\tthis._logger.warn('Auto-adjusted total_thoughts to match thought_number', {\n\t\t\t\tthought_number: input.thought_number,\n\t\t\t\toriginal_total_thoughts: originalTotal,\n\t\t\t\tadjusted_total_thoughts: input.thought_number,\n\t\t\t});\n\t\t\tinput.total_thoughts = input.thought_number;\n\t\t}\n\t\treturn { result: input, warnings };\n\t}\n\n\t/**\n\t * Validates cross-field references against actual thought history.\n\t * Drops invalid references with a warning log — never rejects.\n\t * LLMs frequently send optimistic references to thoughts that don't exist yet.\n\t *\n\t * @param input - The thought data to validate\n\t * @returns Object with cleaned input and any warnings generated\n\t * @private\n\t *\n\t * @example\n\t * ```typescript\n\t * // verification_target=999 with only 3 thoughts in history\n\t * const { result, warnings } = this._validateCrossReferences(input);\n\t * // result.verification_target === undefined\n\t * // warnings === ['Dropped dangling verification_target: 999 (history has 3 thoughts)']\n\t * ```\n\t */\n\tprivate _validateCrossReferences(input: ThoughtData, sessionId?: string): {\n\t\tresult: ThoughtData;\n\t\twarnings: string[];\n\t} {\n\t\tconst warnings: string[] = [];\n\t\tconst historyLength = this.historyManager.getHistoryLength(sessionId);\n\n\t\t// verification_target: must reference existing thought\n\t\tif (input.verification_target !== undefined && input.verification_target > historyLength) {\n\t\t\twarnings.push(\n\t\t\t\t`Dropped dangling verification_target: ${input.verification_target} (history has ${historyLength} thoughts)`\n\t\t\t);\n\t\t\tthis._logger.warn('Dropped dangling verification_target', {\n\t\t\t\tverification_target: input.verification_target,\n\t\t\t\thistoryLength,\n\t\t\t});\n\t\t\tinput.verification_target = undefined;\n\t\t}\n\n\t\t// revises_thought: must reference existing thought\n\t\tif (input.revises_thought !== undefined && input.revises_thought > historyLength) {\n\t\t\twarnings.push(\n\t\t\t\t`Dropped dangling revises_thought: ${input.revises_thought} (history has ${historyLength} thoughts)`\n\t\t\t);\n\t\t\tthis._logger.warn('Dropped dangling revises_thought', {\n\t\t\t\trevises_thought: input.revises_thought,\n\t\t\t\thistoryLength,\n\t\t\t});\n\t\t\tinput.revises_thought = undefined;\n\t\t}\n\n\t\t// branch_from_thought: must reference existing thought\n\t\tif (input.branch_from_thought !== undefined && input.branch_from_thought > historyLength) {\n\t\t\twarnings.push(\n\t\t\t\t`Dropped dangling branch_from_thought: ${input.branch_from_thought} (history has ${historyLength} thoughts)`\n\t\t\t);\n\t\t\tthis._logger.warn('Dropped dangling branch_from_thought', {\n\t\t\t\tbranch_from_thought: input.branch_from_thought,\n\t\t\t\thistoryLength,\n\t\t\t});\n\t\t\tinput.branch_from_thought = undefined;\n\t\t}\n\n\t\t// synthesis_sources: filter to existing thoughts only\n\t\tif (input.synthesis_sources?.length) {\n\t\t\tconst valid = input.synthesis_sources.filter((n: number) => n <= historyLength);\n\t\t\tif (valid.length < input.synthesis_sources.length) {\n\t\t\t\tconst dropped = input.synthesis_sources.filter((n: number) => n > historyLength);\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Filtered dangling synthesis_sources: [${dropped.join(', ')}] (history has ${historyLength} thoughts)`\n\t\t\t\t);\n\t\t\t\tthis._logger.warn('Filtered dangling synthesis_sources', {\n\t\t\t\t\toriginal: input.synthesis_sources,\n\t\t\t\t\tfiltered: valid,\n\t\t\t\t\thistoryLength,\n\t\t\t\t});\n\t\t\t}\n\t\t\tinput.synthesis_sources = valid.length > 0 ? valid : undefined;\n\t\t}\n\n\t\t// merge_from_thoughts: filter to existing thoughts only\n\t\tif (input.merge_from_thoughts?.length) {\n\t\t\tconst valid = input.merge_from_thoughts.filter((n: number) => n <= historyLength);\n\t\t\tif (valid.length < input.merge_from_thoughts.length) {\n\t\t\t\tconst dropped = input.merge_from_thoughts.filter(\n\t\t\t\t\t(n: number) => n > historyLength\n\t\t\t\t);\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Filtered dangling merge_from_thoughts: [${dropped.join(', ')}] (history has ${historyLength} thoughts)`\n\t\t\t\t);\n\t\t\t\tthis._logger.warn('Filtered dangling merge_from_thoughts', {\n\t\t\t\t\toriginal: input.merge_from_thoughts,\n\t\t\t\t\tfiltered: valid,\n\t\t\t\t\thistoryLength,\n\t\t\t\t});\n\t\t\t}\n\t\t\tinput.merge_from_thoughts = valid.length > 0 ? valid : undefined;\n\t\t}\n\n\t\t// merge_branch_ids: filter to existing branches only (includes pre-registered)\n\t\tif (input.merge_branch_ids?.length) {\n\t\t\tconst valid = input.merge_branch_ids.filter((id: string) =>\n\t\t\t\tthis.historyManager.branchExists(sessionId, id)\n\t\t\t);\n\t\t\tif (valid.length < input.merge_branch_ids.length) {\n\t\t\t\tconst dropped = input.merge_branch_ids.filter(\n\t\t\t\t\t(id: string) => !this.historyManager.branchExists(sessionId, id)\n\t\t\t\t);\n\t\t\t\twarnings.push(`Filtered dangling merge_branch_ids: [${dropped.join(', ')}]`);\n\t\t\t\tthis._logger.warn('Filtered dangling merge_branch_ids', {\n\t\t\t\t\toriginal: input.merge_branch_ids,\n\t\t\t\t\tfiltered: valid,\n\t\t\t\t\texistingBranches: this.historyManager.getBranchIds(sessionId),\n\t\t\t\t});\n\t\t\t}\n\t\t\tinput.merge_branch_ids = valid.length > 0 ? valid : undefined;\n\t\t}\n\n\t\treturn { result: input, warnings };\n\t}\n\n\t/**\n\t * Validate new thought-type invariants behind feature flags.\n\t * @private\n\t */\n\tprivate _validateNewTypes(input: ThoughtData, sessionId?: string): void {\n\t\tconst t = input.thought_type;\n\t\tif ((t === 'tool_call' || t === 'tool_observation') && !this._features.toolInterleave) {\n\t\t\tthrow new ValidationError(\n\t\t\t\t'thought_type',\n\t\t\t\t`Type '${t}' requires the toolInterleave feature flag. Set TRACELATTICE_FEATURES_TOOL_INTERLEAVE=true to enable it.`\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\t(t === 'assumption' || t === 'decomposition' || t === 'backtrack') &&\n\t\t\t!this._features.newThoughtTypes\n\t\t) {\n\t\t\tthrow new ValidationError(\n\t\t\t\t'thought_type',\n\t\t\t\t`Type '${t}' requires the newThoughtTypes feature flag. Set TRACELATTICE_FEATURES_NEW_THOUGHT_TYPES=true to enable it, or use '${ThoughtProcessor._getWorkaroundType(t)}' type as a workaround.`\n\t\t\t);\n\t\t}\n\t\tif (t === 'tool_call' && !input.tool_name) {\n\t\t\tthrow new InvalidToolCallError(\n\t\t\t\t'tool_call thought ' + input.thought_number + ' missing required tool_name'\n\t\t\t);\n\t\t}\n\t\tif (t === 'tool_observation' && !input.continuation_token) {\n\t\t\tthrow new ValidationError(\n\t\t\t\t'continuation_token',\n\t\t\t\t'tool_observation thought ' + input.thought_number + ' missing continuation_token'\n\t\t\t);\n\t\t}\n\t\tif (t === 'backtrack') {\n\t\t\tif (input.backtrack_target === undefined) {\n\t\t\t\tthrow new ValidationError(\n\t\t\t\t\t'backtrack_target',\n\t\t\t\t\t'backtrack thought ' + input.thought_number + ' requires backtrack_target'\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (input.backtrack_target > input.thought_number) {\n\t\t\t\tthrow new InvalidBacktrackError(\n\t\t\t\t\t'backtrack_target ' + input.backtrack_target + ' must be <= thought_number ' + input.thought_number\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!this._thoughtNumberExists(input.backtrack_target, sessionId)) {\n\t\t\t\tthrow new InvalidBacktrackError(\n\t\t\t\t\t'backtrack_target ' + input.backtrack_target + ' does not exist in session history'\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether a given thought_number exists in the session history or any branch.\n\t * @private\n\t */\n\tprivate _thoughtNumberExists(thoughtNumber: number, sessionId?: string): boolean {\n\t\tconst history = this.historyManager.getHistory(sessionId);\n\t\tfor (const t of history) {\n\t\t\tif (t.thought_number === thoughtNumber) return true;\n\t\t}\n\t\tconst branches = this.historyManager.getBranches(sessionId);\n\t\tfor (const branchThoughts of Object.values(branches)) {\n\t\t\tfor (const t of branchThoughts) {\n\t\t\t\tif (t.thought_number === thoughtNumber) return true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Returns a workaround thought type for a feature-flagged type.\n\t * @private\n\t */\n\tprivate static _getWorkaroundType(t: 'assumption' | 'decomposition' | 'backtrack'): string {\n\t\tswitch (t) {\n\t\t\tcase 'assumption':\n\t\t\t\treturn 'regular';\n\t\t\tcase 'decomposition':\n\t\t\t\treturn 'hypothesis';\n\t\t\tcase 'backtrack':\n\t\t\t\treturn 'regular';\n\t\t}\n\t}\n\n\t/**\n\t * Persist a tool_call thought and return a `suspended` envelope.\n\t * Strategy/evaluator are intentionally skipped.\n\t * @private\n\t */\n\tprivate _handleToolCall(input: ThoughtData, sessionId?: string): CallToolResult {\n\t\tthis.historyManager.addThought(input);\n\t\tconst record: SuspensionRecord = this._suspensionStore!.suspend({\n\t\t\tsessionId: sessionId ?? '__global__',\n\t\t\ttoolCallThoughtNumber: input.thought_number,\n\t\t\ttoolName: input.tool_name!,\n\t\t\ttoolArguments: input.tool_arguments ?? {},\n\t\t\tttlMs: 5 * 60_000,\n\t\t\texpiresAt: 0,\n\t\t});\n\t\treturn {\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'text' as const,\n\t\t\t\t\ttext: JSON.stringify(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 'suspended',\n\t\t\t\t\t\t\tcontinuation_token: record.token,\n\t\t\t\t\t\t\ttool_name: record.toolName,\n\t\t\t\t\t\t\ttool_arguments: record.toolArguments,\n\t\t\t\t\t\t\texpires_at: record.expiresAt,\n\t\t\t\t\t\t\tthought_number: input.thought_number,\n\t\t\t\t\t\t\ttotal_thoughts: input.total_thoughts,\n\t\t\t\t\t\t\t...(sessionId ? { session_id: sessionId } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t2\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t}\n\n\t/**\n\t * Resume from a tool_observation, consuming the suspension record.\n\t * Distinguishes missing vs expired via peek().\n\t * @private\n\t */\n\tprivate _handleToolObservation(input: ThoughtData, _sessionId?: string): void {\n\t\tconst token = input.continuation_token!;\n\t\tconst peeked = this._suspensionStore!.peek(token);\n\t\tif (peeked && peeked.expiresAt <= Date.now()) {\n\t\t\tthrow new SuspensionExpiredError('Suspension token expired: ' + token);\n\t\t}\n\t\tconst record = this._suspensionStore!.resume(token);\n\t\tif (!record) {\n\t\t\tthrow new SuspensionNotFoundError('Suspension token not found: ' + token);\n\t\t}\n\t\t(input as ResumableThought)._resumedFrom = record.toolCallThoughtNumber;\n\t}\n}\n"],"names":["DEFAULT_FEATURES","ThoughtProcessor","Map","historyManager","thoughtFormatter","thoughtEvaluator","logger","strategy","SequentialStrategy","_compressionService","_suspensionStore","_features","NullLogger","message","meta","patterns","currentThoughtNumber","sessionId","warnings","p","a","b","pa","pb","sessionKey","cooldowns","hints","warning","lastFired","undefined","input","normalizedInput","normalizeInput","validatedInput","validateWarnings","checkedInput","refWarnings","allWarnings","formattedThought","history","branches","confidenceSignals","reasoningStats","patternSignals","reasoningHints","decision","JSON","error","getErrorMessage","currentThought","stats","edgeStore","graph","GraphView","sid","branchRoot","err","branchId","branchList","firstId","ids","hm","originalTotal","historyLength","valid","n","dropped","id","t","ValidationError","InvalidToolCallError","InvalidBacktrackError","thoughtNumber","branchThoughts","Object","record","_sessionId","token","peeked","Date","SuspensionExpiredError","SuspensionNotFoundError"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Aggregator.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/Aggregator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"Aggregator.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/Aggregator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAajD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,UAAU;IACtB;;;;;;;OAOG;IACI,qBAAqB,CAC3B,OAAO,EAAE,WAAW,EAAE,EACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,GACrC,cAAc;CAwCjB"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { _computeChainDepth, _countByType } from "./internals.js";
|
|
2
|
+
function roundToPrecision(value, decimals = 10) {
|
|
3
|
+
const factor = Math.pow(10, decimals);
|
|
4
|
+
return Math.round(value * factor) / factor;
|
|
5
|
+
}
|
|
2
6
|
class Aggregator {
|
|
3
7
|
computeReasoningStats(history, branches) {
|
|
4
8
|
const typeCounts = _countByType(history);
|
|
@@ -22,8 +26,8 @@ class Aggregator {
|
|
|
22
26
|
...hypothesisIds
|
|
23
27
|
].filter((id)=>verifiedIds.has(id)).length,
|
|
24
28
|
unresolved_hypothesis_count: unresolvedCount,
|
|
25
|
-
average_quality_score: allScores.length > 0 ? allScores.reduce((a, b)=>a + b, 0) / allScores.length : null,
|
|
26
|
-
average_confidence: allConfidences.length > 0 ? allConfidences.reduce((a, b)=>a + b, 0) / allConfidences.length : null
|
|
29
|
+
average_quality_score: allScores.length > 0 ? roundToPrecision(allScores.reduce((a, b)=>a + b, 0) / allScores.length) : null,
|
|
30
|
+
average_confidence: allConfidences.length > 0 ? roundToPrecision(allConfidences.reduce((a, b)=>a + b, 0) / allConfidences.length) : null
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/evaluator/Aggregator.js","sources":["../../../src/core/evaluator/Aggregator.ts"],"sourcesContent":["/**\n * Reasoning analytics aggregation.\n *\n * Provides the {@link Aggregator} class — a stateless service that computes\n * aggregated {@link ReasoningStats} from thought history and branch data.\n * Extracted from {@link ThoughtEvaluator} to isolate the stats-aggregation\n * concern.\n *\n * @module core/evaluator/Aggregator\n */\n\nimport type { ReasoningStats } from '../reasoning.js';\nimport type { ThoughtData } from '../thought.js';\nimport { _computeChainDepth, _countByType } from './internals.js';\n\n/**\n * Stateless service that aggregates reasoning analytics from thought\n * history and branch data.\n *\n * @remarks\n * All methods are pure computations — no side effects, no I/O, no\n * internal state. Designed to be registered as transient in the DI\n * container.\n *\n * @example\n * ```typescript\n * const aggregator = new Aggregator();\n * const stats = aggregator.computeReasoningStats(history, branches);\n * console.log(stats.total_thoughts); // 12\n * ```\n */\nexport class Aggregator {\n\t/**\n\t * Compute aggregated reasoning analytics.\n\t * Pure computation from history + branches.\n\t *\n\t * @param history - All thoughts in the current session\n\t * @param branches - Map of branch IDs to their thought arrays\n\t * @returns Aggregated reasoning statistics for the session\n\t */\n\tpublic computeReasoningStats(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>\n\t): ReasoningStats {\n\t\tconst typeCounts = _countByType(history);\n\t\tconst allScores = history\n\t\t\t.map((t) => t.quality_score)\n\t\t\t.filter((s): s is number => s !== undefined);\n\t\tconst allConfidences = history\n\t\t\t.map((t) => t.confidence)\n\t\t\t.filter((c): c is number => c !== undefined);\n\n\t\tconst hypotheses = history.filter((t) => t.thought_type === 'hypothesis');\n\t\tconst hypothesisIds = new Set(hypotheses.map((t) => t.hypothesis_id).filter(Boolean));\n\t\tconst verifiedIds = new Set(\n\t\t\thistory\n\t\t\t\t.filter((t) => t.thought_type === 'verification' && t.hypothesis_id)\n\t\t\t\t.map((t) => t.hypothesis_id)\n\t\t);\n\t\tconst unresolvedCount = [...hypothesisIds].filter((id) => !verifiedIds.has(id)).length;\n\n\t\treturn {\n\t\t\ttotal_thoughts: history.length,\n\t\t\ttotal_branches: Object.keys(branches).length,\n\t\t\ttotal_revisions: history.filter((t) => t.is_revision).length,\n\t\t\ttotal_merges: history.filter(\n\t\t\t\t(t) => (t.merge_from_thoughts?.length ?? 0) > 0 || (t.merge_branch_ids?.length ?? 0) > 0\n\t\t\t).length,\n\t\t\tchain_depth: _computeChainDepth(history),\n\t\t\tthought_type_counts: typeCounts,\n\t\t\thypothesis_count: hypothesisIds.size,\n\t\t\tverified_hypothesis_count: [...hypothesisIds].filter((id) => verifiedIds.has(id)).length,\n\t\t\tunresolved_hypothesis_count: unresolvedCount,\n\t\t\taverage_quality_score:\n\t\t\t\tallScores.length > 0
|
|
1
|
+
{"version":3,"file":"core/evaluator/Aggregator.js","sources":["../../../src/core/evaluator/Aggregator.ts"],"sourcesContent":["/**\n * Reasoning analytics aggregation.\n *\n * Provides the {@link Aggregator} class — a stateless service that computes\n * aggregated {@link ReasoningStats} from thought history and branch data.\n * Extracted from {@link ThoughtEvaluator} to isolate the stats-aggregation\n * concern.\n *\n * @module core/evaluator/Aggregator\n */\n\nimport type { ReasoningStats } from '../reasoning.js';\nimport type { ThoughtData } from '../thought.js';\nimport { _computeChainDepth, _countByType } from './internals.js';\n\n/**\n * Round a numeric value to a fixed number of decimal places to mitigate\n * IEEE 754 floating-point accumulation errors (e.g. 0.9 + 0.8 averaging to\n * 0.8500000000000001 instead of 0.85).\n */\nfunction roundToPrecision(value: number, decimals: number = 10): number {\n\tconst factor = Math.pow(10, decimals);\n\treturn Math.round(value * factor) / factor;\n}\n\n/**\n * Stateless service that aggregates reasoning analytics from thought\n * history and branch data.\n *\n * @remarks\n * All methods are pure computations — no side effects, no I/O, no\n * internal state. Designed to be registered as transient in the DI\n * container.\n *\n * @example\n * ```typescript\n * const aggregator = new Aggregator();\n * const stats = aggregator.computeReasoningStats(history, branches);\n * console.log(stats.total_thoughts); // 12\n * ```\n */\nexport class Aggregator {\n\t/**\n\t * Compute aggregated reasoning analytics.\n\t * Pure computation from history + branches.\n\t *\n\t * @param history - All thoughts in the current session\n\t * @param branches - Map of branch IDs to their thought arrays\n\t * @returns Aggregated reasoning statistics for the session\n\t */\n\tpublic computeReasoningStats(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>\n\t): ReasoningStats {\n\t\tconst typeCounts = _countByType(history);\n\t\tconst allScores = history\n\t\t\t.map((t) => t.quality_score)\n\t\t\t.filter((s): s is number => s !== undefined);\n\t\tconst allConfidences = history\n\t\t\t.map((t) => t.confidence)\n\t\t\t.filter((c): c is number => c !== undefined);\n\n\t\tconst hypotheses = history.filter((t) => t.thought_type === 'hypothesis');\n\t\tconst hypothesisIds = new Set(hypotheses.map((t) => t.hypothesis_id).filter(Boolean));\n\t\tconst verifiedIds = new Set(\n\t\t\thistory\n\t\t\t\t.filter((t) => t.thought_type === 'verification' && t.hypothesis_id)\n\t\t\t\t.map((t) => t.hypothesis_id)\n\t\t);\n\t\tconst unresolvedCount = [...hypothesisIds].filter((id) => !verifiedIds.has(id)).length;\n\n\t\treturn {\n\t\t\ttotal_thoughts: history.length,\n\t\t\ttotal_branches: Object.keys(branches).length,\n\t\t\ttotal_revisions: history.filter((t) => t.is_revision).length,\n\t\t\ttotal_merges: history.filter(\n\t\t\t\t(t) => (t.merge_from_thoughts?.length ?? 0) > 0 || (t.merge_branch_ids?.length ?? 0) > 0\n\t\t\t).length,\n\t\t\tchain_depth: _computeChainDepth(history),\n\t\t\tthought_type_counts: typeCounts,\n\t\t\thypothesis_count: hypothesisIds.size,\n\t\t\tverified_hypothesis_count: [...hypothesisIds].filter((id) => verifiedIds.has(id)).length,\n\t\t\tunresolved_hypothesis_count: unresolvedCount,\n\t\t\taverage_quality_score:\n\t\t\t\tallScores.length > 0\n\t\t\t\t\t? roundToPrecision(allScores.reduce((a, b) => a + b, 0) / allScores.length)\n\t\t\t\t\t: null,\n\t\t\taverage_confidence:\n\t\t\t\tallConfidences.length > 0\n\t\t\t\t\t? roundToPrecision(allConfidences.reduce((a, b) => a + b, 0) / allConfidences.length)\n\t\t\t\t\t: null,\n\t\t};\n\t}\n}\n"],"names":["roundToPrecision","value","decimals","factor","Math","Aggregator","history","branches","typeCounts","_countByType","allScores","t","s","undefined","allConfidences","c","hypotheses","hypothesisIds","Set","Boolean","verifiedIds","unresolvedCount","id","Object","_computeChainDepth","a","b"],"mappings":";AAoBA,SAASA,iBAAiBC,KAAa,EAAEC,WAAmB,EAAE;IAC7D,MAAMC,SAASC,KAAK,GAAG,CAAC,IAAIF;IAC5B,OAAOE,KAAK,KAAK,CAACH,QAAQE,UAAUA;AACrC;AAkBO,MAAME;IASL,sBACNC,OAAsB,EACtBC,QAAuC,EACtB;QACjB,MAAMC,aAAaC,aAAaH;QAChC,MAAMI,YAAYJ,QAChB,GAAG,CAAC,CAACK,IAAMA,EAAE,aAAa,EAC1B,MAAM,CAAC,CAACC,IAAmBA,AAAMC,WAAND;QAC7B,MAAME,iBAAiBR,QACrB,GAAG,CAAC,CAACK,IAAMA,EAAE,UAAU,EACvB,MAAM,CAAC,CAACI,IAAmBA,AAAMF,WAANE;QAE7B,MAAMC,aAAaV,QAAQ,MAAM,CAAC,CAACK,IAAMA,AAAmB,iBAAnBA,EAAE,YAAY;QACvD,MAAMM,gBAAgB,IAAIC,IAAIF,WAAW,GAAG,CAAC,CAACL,IAAMA,EAAE,aAAa,EAAE,MAAM,CAACQ;QAC5E,MAAMC,cAAc,IAAIF,IACvBZ,QACE,MAAM,CAAC,CAACK,IAAMA,AAAmB,mBAAnBA,EAAE,YAAY,IAAuBA,EAAE,aAAa,EAClE,GAAG,CAAC,CAACA,IAAMA,EAAE,aAAa;QAE7B,MAAMU,kBAAkB;eAAIJ;SAAc,CAAC,MAAM,CAAC,CAACK,KAAO,CAACF,YAAY,GAAG,CAACE,KAAK,MAAM;QAEtF,OAAO;YACN,gBAAgBhB,QAAQ,MAAM;YAC9B,gBAAgBiB,OAAO,IAAI,CAAChB,UAAU,MAAM;YAC5C,iBAAiBD,QAAQ,MAAM,CAAC,CAACK,IAAMA,EAAE,WAAW,EAAE,MAAM;YAC5D,cAAcL,QAAQ,MAAM,CAC3B,CAACK,IAAOA,AAAAA,CAAAA,EAAE,mBAAmB,EAAE,UAAU,KAAK,KAAMA,AAAAA,CAAAA,EAAE,gBAAgB,EAAE,UAAU,KAAK,GACtF,MAAM;YACR,aAAaa,mBAAmBlB;YAChC,qBAAqBE;YACrB,kBAAkBS,cAAc,IAAI;YACpC,2BAA2B;mBAAIA;aAAc,CAAC,MAAM,CAAC,CAACK,KAAOF,YAAY,GAAG,CAACE,KAAK,MAAM;YACxF,6BAA6BD;YAC7B,uBACCX,UAAU,MAAM,GAAG,IAChBV,iBAAiBU,UAAU,MAAM,CAAC,CAACe,GAAGC,IAAMD,IAAIC,GAAG,KAAKhB,UAAU,MAAM,IACxE;YACJ,oBACCI,eAAe,MAAM,GAAG,IACrBd,iBAAiBc,eAAe,MAAM,CAAC,CAACW,GAAGC,IAAMD,IAAIC,GAAG,KAAKZ,eAAe,MAAM,IAClF;QACL;IACD;AACD"}
|
|
@@ -68,7 +68,7 @@ class PatternDetector {
|
|
|
68
68
|
return [
|
|
69
69
|
{
|
|
70
70
|
pattern: 'no_alternatives_explored',
|
|
71
|
-
severity: '
|
|
71
|
+
severity: 'warning',
|
|
72
72
|
message: '5+ thoughts with no critique or branching — consider exploring alternatives',
|
|
73
73
|
thought_range: [
|
|
74
74
|
start,
|
|
@@ -104,7 +104,7 @@ class PatternDetector {
|
|
|
104
104
|
const end = history[runStart + runLength - 1].thought_number ?? runStart + runLength;
|
|
105
105
|
signals.push({
|
|
106
106
|
pattern: 'monotonic_type',
|
|
107
|
-
severity: '
|
|
107
|
+
severity: 'warning',
|
|
108
108
|
message: `4+ consecutive '${runType}' thoughts (${start}-${end}) — consider varying approach`,
|
|
109
109
|
thought_range: [
|
|
110
110
|
start,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/evaluator/PatternDetector.js","sources":["../../../src/core/evaluator/PatternDetector.ts"],"sourcesContent":["/**\n * Pattern detection for sequential thinking reasoning analytics.\n *\n * Provides the {@link PatternDetector} class — a stateless service that detects\n * reasoning patterns (anti-patterns and positive signals) from thought history.\n * Extracted from {@link ThoughtEvaluator} to keep concerns isolated and reduce\n * cyclomatic complexity per function.\n *\n * Detected patterns:\n * - `consecutive_without_verification` (warning) — 3+ consecutive regular thoughts\n * without a verification step\n * - `unverified_hypothesis` (warning) — hypothesis not verified within 3 subsequent\n * thoughts\n * - `no_alternatives_explored` (info) — 5+ thoughts with no critique and no branches\n * - `monotonic_type` (info) — 4+ consecutive thoughts with the same thought_type\n * (requires ≥1 explicit type and ≥5 thoughts)\n * - `confidence_drift` (warning) — 3+ consecutive thoughts with strictly decreasing\n * confidence\n * - `healthy_verification` (info) — hypothesis verified within 3 subsequent thoughts\n *\n * @module core/evaluator/PatternDetector\n */\n\nimport type { PatternSignal } from '../reasoning.js';\nimport type { ThoughtData } from '../thought.js';\n\n/**\n * Stateless service that detects reasoning patterns from thought history.\n *\n * @remarks\n * All methods are pure computations — no side effects, no I/O, no internal state.\n * Designed to be registered as transient in the DI container or composed directly\n * into {@link ThoughtEvaluator}.\n *\n * @example\n * ```typescript\n * const detector = new PatternDetector();\n * const signals = detector.computePatternSignals(history, branches);\n * const warnings = signals.filter((s) => s.severity === 'warning');\n * ```\n */\nexport class PatternDetector {\n\t/**\n\t * Detect all reasoning patterns from history and branches.\n\t *\n\t * @param history - All thoughts in the current session\n\t * @param branches - Map of branch IDs to their thought arrays\n\t * @returns Array of detected pattern signals (possibly empty)\n\t */\n\tpublic computePatternSignals(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>\n\t): PatternSignal[] {\n\t\tif (history.length === 0) return [];\n\n\t\tconst signals: PatternSignal[] = [];\n\t\tsignals.push(...this._detectConsecutiveWithoutVerification(history));\n\t\tsignals.push(...this._detectUnverifiedHypothesis(history));\n\t\tsignals.push(...this._detectNoAlternativesExplored(history, branches));\n\t\tsignals.push(...this._detectMonotonicType(history));\n\t\tsignals.push(...this._detectConfidenceDrift(history));\n\t\tsignals.push(...this._detectHealthyVerification(history));\n\t\treturn signals;\n\t}\n\n\t/** Detect runs of 3+ consecutive thoughts without verification. */\n\tprivate _detectConsecutiveWithoutVerification(history: ThoughtData[]): PatternSignal[] {\n\t\tconst signals: PatternSignal[] = [];\n\t\tlet runStart = 0;\n\t\tfor (let i = 0; i < history.length; i++) {\n\t\t\tconst type = history[i]!.thought_type ?? 'regular';\n\t\t\tif (type === 'verification') {\n\t\t\t\trunStart = i + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (i - runStart + 1 >= 3) {\n\t\t\t\tconst start = history[runStart]!.thought_number ?? runStart + 1;\n\t\t\t\tconst end = history[i]!.thought_number ?? i + 1;\n\t\t\t\tsignals.push({\n\t\t\t\t\tpattern: 'consecutive_without_verification',\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\tmessage: `3+ consecutive thoughts (${start}-${end}) without verification`,\n\t\t\t\t\tthought_range: [start, end],\n\t\t\t\t});\n\t\t\t\trunStart = i + 1;\n\t\t\t}\n\t\t}\n\t\treturn signals;\n\t}\n\n\t/** Detect hypothesis thoughts not verified within 3 subsequent thoughts. */\n\tprivate _detectUnverifiedHypothesis(history: ThoughtData[]): PatternSignal[] {\n\t\tconst signals: PatternSignal[] = [];\n\t\tfor (let i = 0; i < history.length; i++) {\n\t\t\tif (history[i]!.thought_type !== 'hypothesis') continue;\n\t\t\tconst remaining = history.length - i - 1;\n\t\t\tif (remaining < 3) continue;\n\t\t\tconst lookahead = history.slice(i + 1, i + 4);\n\t\t\tconst hasVerification = lookahead.some((t) => t.thought_type === 'verification');\n\t\t\tif (!hasVerification) {\n\t\t\t\tconst n = history[i]!.thought_number ?? i + 1;\n\t\t\t\tsignals.push({\n\t\t\t\t\tpattern: 'unverified_hypothesis',\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\tmessage: `Hypothesis at thought ${n} has not been verified within 3 thoughts`,\n\t\t\t\t\tthought_range: [n, n],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn signals;\n\t}\n\n\t/** Detect 5+ thoughts with no critique and no branches. */\n\tprivate _detectNoAlternativesExplored(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>\n\t): PatternSignal[] {\n\t\tif (history.length < 5) return [];\n\t\tif (history.some((t) => t.thought_type === 'critique')) return [];\n\t\tif (Object.keys(branches).length > 0) return [];\n\t\tconst start = history[0]!.thought_number ?? 1;\n\t\tconst end = history[history.length - 1]!.thought_number ?? history.length;\n\t\treturn [\n\t\t\t{\n\t\t\t\tpattern: 'no_alternatives_explored',\n\t\t\t\tseverity: 'info',\n\t\t\t\tmessage: '5+ thoughts with no critique or branching — consider exploring alternatives',\n\t\t\t\tthought_range: [start, end],\n\t\t\t},\n\t\t];\n\t}\n\n\t/**\n\t * Detect runs of 4+ consecutive thoughts with the same thought_type.\n\t * Only fires when history has ≥5 thoughts and at least one explicitly set thought_type.\n\t */\n\tprivate _detectMonotonicType(history: ThoughtData[]): PatternSignal[] {\n\t\tif (history.length < 5) return [];\n\t\tconst hasExplicitType = history.some((t) => t.thought_type !== undefined);\n\t\tif (!hasExplicitType) return [];\n\n\t\tconst signals: PatternSignal[] = [];\n\t\tlet runType = history[0]!.thought_type ?? 'regular';\n\t\tlet runStart = 0;\n\t\tlet runLength = 1;\n\n\t\tfor (let i = 1; i < history.length; i++) {\n\t\t\tconst type = history[i]!.thought_type ?? 'regular';\n\t\t\tif (type === runType) {\n\t\t\t\trunLength++;\n\t\t\t} else {\n\t\t\t\tthis._flushMonotonicRun(history, runStart, runLength, runType, signals);\n\t\t\t\trunType = type;\n\t\t\t\trunStart = i;\n\t\t\t\trunLength = 1;\n\t\t\t}\n\t\t}\n\t\tthis._flushMonotonicRun(history, runStart, runLength, runType, signals);\n\t\treturn signals;\n\t}\n\n\t/** Emit a monotonic_type signal if the run length qualifies. */\n\tprivate _flushMonotonicRun(\n\t\thistory: ThoughtData[],\n\t\trunStart: number,\n\t\trunLength: number,\n\t\trunType: string,\n\t\tsignals: PatternSignal[]\n\t): void {\n\t\tif (runLength < 4) return;\n\t\tconst start = history[runStart]!.thought_number ?? runStart + 1;\n\t\tconst end = history[runStart + runLength - 1]!.thought_number ?? runStart + runLength;\n\t\tsignals.push({\n\t\t\tpattern: 'monotonic_type',\n\t\t\tseverity: 'info',\n\t\t\tmessage: `4+ consecutive '${runType}' thoughts (${start}-${end}) — consider varying approach`,\n\t\t\tthought_range: [start, end],\n\t\t});\n\t}\n\n\t/** Detect runs of 3+ consecutive thoughts with strictly decreasing confidence. */\n\tprivate _detectConfidenceDrift(history: ThoughtData[]): PatternSignal[] {\n\t\tconst signals: PatternSignal[] = [];\n\t\tlet runStart = -1;\n\t\tlet runLength = 0;\n\t\tlet prevConf = -1;\n\n\t\tfor (let i = 0; i < history.length; i++) {\n\t\t\tconst conf = history[i]!.confidence;\n\t\t\tif (conf === undefined) {\n\t\t\t\tthis._flushDriftRun(history, runStart, runLength, signals);\n\t\t\t\trunStart = -1;\n\t\t\t\trunLength = 0;\n\t\t\t\tprevConf = -1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (runLength === 0) {\n\t\t\t\trunStart = i;\n\t\t\t\trunLength = 1;\n\t\t\t\tprevConf = conf;\n\t\t\t} else if (conf < prevConf) {\n\t\t\t\trunLength++;\n\t\t\t\tprevConf = conf;\n\t\t\t} else {\n\t\t\t\tthis._flushDriftRun(history, runStart, runLength, signals);\n\t\t\t\trunStart = i;\n\t\t\t\trunLength = 1;\n\t\t\t\tprevConf = conf;\n\t\t\t}\n\t\t}\n\t\tthis._flushDriftRun(history, runStart, runLength, signals);\n\t\treturn signals;\n\t}\n\n\t/** Emit a confidence_drift signal if the run length qualifies. */\n\tprivate _flushDriftRun(\n\t\thistory: ThoughtData[],\n\t\trunStart: number,\n\t\trunLength: number,\n\t\tsignals: PatternSignal[]\n\t): void {\n\t\tif (runLength < 3) return;\n\t\tconst start = history[runStart]!.thought_number ?? runStart + 1;\n\t\tconst end = history[runStart + runLength - 1]!.thought_number ?? runStart + runLength;\n\t\tconst firstConf = history[runStart]!.confidence!;\n\t\tconst lastConf = history[runStart + runLength - 1]!.confidence!;\n\t\tsignals.push({\n\t\t\tpattern: 'confidence_drift',\n\t\t\tseverity: 'warning',\n\t\t\tmessage: `Confidence decreasing across thoughts ${start}-${end} (${firstConf} → ${lastConf})`,\n\t\t\tthought_range: [start, end],\n\t\t});\n\t}\n\n\t/** Detect hypothesis verified within 3 subsequent thoughts — positive signal. */\n\tprivate _detectHealthyVerification(history: ThoughtData[]): PatternSignal[] {\n\t\tconst signals: PatternSignal[] = [];\n\t\tfor (let i = 0; i < history.length; i++) {\n\t\t\tif (history[i]!.thought_type !== 'hypothesis') continue;\n\t\t\tconst hypId = history[i]!.hypothesis_id;\n\t\t\tconst lookahead = history.slice(i + 1, i + 4);\n\t\t\tconst verifier = lookahead.find(\n\t\t\t\t(t) =>\n\t\t\t\t\tt.thought_type === 'verification' &&\n\t\t\t\t\t(t.hypothesis_id === hypId ||\n\t\t\t\t\t\tt.verification_target === (history[i]!.thought_number ?? i + 1))\n\t\t\t);\n\t\t\tif (verifier) {\n\t\t\t\tconst n = history[i]!.thought_number ?? i + 1;\n\t\t\t\tconst m = verifier.thought_number ?? history.indexOf(verifier) + 1;\n\t\t\t\tsignals.push({\n\t\t\t\t\tpattern: 'healthy_verification',\n\t\t\t\t\tseverity: 'info',\n\t\t\t\t\tmessage: `Hypothesis at thought ${n} verified at thought ${m} — good practice`,\n\t\t\t\t\tthought_range: [n, m],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn signals;\n\t}\n}\n"],"names":["PatternDetector","history","branches","signals","runStart","i","type","start","end","remaining","lookahead","hasVerification","t","n","Object","hasExplicitType","undefined","runType","runLength","prevConf","conf","firstConf","lastConf","hypId","verifier","m"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core/evaluator/PatternDetector.js","sources":["../../../src/core/evaluator/PatternDetector.ts"],"sourcesContent":["/**\n * Pattern detection for sequential thinking reasoning analytics.\n *\n * Provides the {@link PatternDetector} class — a stateless service that detects\n * reasoning patterns (anti-patterns and positive signals) from thought history.\n * Extracted from {@link ThoughtEvaluator} to keep concerns isolated and reduce\n * cyclomatic complexity per function.\n *\n * Detected patterns:\n * - `consecutive_without_verification` (warning) — 3+ consecutive regular thoughts\n * without a verification step\n * - `unverified_hypothesis` (warning) — hypothesis not verified within 3 subsequent\n * thoughts\n * - `no_alternatives_explored` (info) — 5+ thoughts with no critique and no branches\n * - `monotonic_type` (info) — 4+ consecutive thoughts with the same thought_type\n * (requires ≥1 explicit type and ≥5 thoughts)\n * - `confidence_drift` (warning) — 3+ consecutive thoughts with strictly decreasing\n * confidence\n * - `healthy_verification` (info) — hypothesis verified within 3 subsequent thoughts\n *\n * @module core/evaluator/PatternDetector\n */\n\nimport type { PatternSignal } from '../reasoning.js';\nimport type { ThoughtData } from '../thought.js';\n\n/**\n * Stateless service that detects reasoning patterns from thought history.\n *\n * @remarks\n * All methods are pure computations — no side effects, no I/O, no internal state.\n * Designed to be registered as transient in the DI container or composed directly\n * into {@link ThoughtEvaluator}.\n *\n * @example\n * ```typescript\n * const detector = new PatternDetector();\n * const signals = detector.computePatternSignals(history, branches);\n * const warnings = signals.filter((s) => s.severity === 'warning');\n * ```\n */\nexport class PatternDetector {\n\t/**\n\t * Detect all reasoning patterns from history and branches.\n\t *\n\t * @param history - All thoughts in the current session\n\t * @param branches - Map of branch IDs to their thought arrays\n\t * @returns Array of detected pattern signals (possibly empty)\n\t */\n\tpublic computePatternSignals(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>\n\t): PatternSignal[] {\n\t\tif (history.length === 0) return [];\n\n\t\tconst signals: PatternSignal[] = [];\n\t\tsignals.push(...this._detectConsecutiveWithoutVerification(history));\n\t\tsignals.push(...this._detectUnverifiedHypothesis(history));\n\t\tsignals.push(...this._detectNoAlternativesExplored(history, branches));\n\t\tsignals.push(...this._detectMonotonicType(history));\n\t\tsignals.push(...this._detectConfidenceDrift(history));\n\t\tsignals.push(...this._detectHealthyVerification(history));\n\t\treturn signals;\n\t}\n\n\t/** Detect runs of 3+ consecutive thoughts without verification. */\n\tprivate _detectConsecutiveWithoutVerification(history: ThoughtData[]): PatternSignal[] {\n\t\tconst signals: PatternSignal[] = [];\n\t\tlet runStart = 0;\n\t\tfor (let i = 0; i < history.length; i++) {\n\t\t\tconst type = history[i]!.thought_type ?? 'regular';\n\t\t\tif (type === 'verification') {\n\t\t\t\trunStart = i + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (i - runStart + 1 >= 3) {\n\t\t\t\tconst start = history[runStart]!.thought_number ?? runStart + 1;\n\t\t\t\tconst end = history[i]!.thought_number ?? i + 1;\n\t\t\t\tsignals.push({\n\t\t\t\t\tpattern: 'consecutive_without_verification',\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\tmessage: `3+ consecutive thoughts (${start}-${end}) without verification`,\n\t\t\t\t\tthought_range: [start, end],\n\t\t\t\t});\n\t\t\t\trunStart = i + 1;\n\t\t\t}\n\t\t}\n\t\treturn signals;\n\t}\n\n\t/** Detect hypothesis thoughts not verified within 3 subsequent thoughts. */\n\tprivate _detectUnverifiedHypothesis(history: ThoughtData[]): PatternSignal[] {\n\t\tconst signals: PatternSignal[] = [];\n\t\tfor (let i = 0; i < history.length; i++) {\n\t\t\tif (history[i]!.thought_type !== 'hypothesis') continue;\n\t\t\tconst remaining = history.length - i - 1;\n\t\t\tif (remaining < 3) continue;\n\t\t\tconst lookahead = history.slice(i + 1, i + 4);\n\t\t\tconst hasVerification = lookahead.some((t) => t.thought_type === 'verification');\n\t\t\tif (!hasVerification) {\n\t\t\t\tconst n = history[i]!.thought_number ?? i + 1;\n\t\t\t\tsignals.push({\n\t\t\t\t\tpattern: 'unverified_hypothesis',\n\t\t\t\t\tseverity: 'warning',\n\t\t\t\t\tmessage: `Hypothesis at thought ${n} has not been verified within 3 thoughts`,\n\t\t\t\t\tthought_range: [n, n],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn signals;\n\t}\n\n\t/** Detect 5+ thoughts with no critique and no branches. */\n\tprivate _detectNoAlternativesExplored(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>\n\t): PatternSignal[] {\n\t\tif (history.length < 5) return [];\n\t\tif (history.some((t) => t.thought_type === 'critique')) return [];\n\t\tif (Object.keys(branches).length > 0) return [];\n\t\tconst start = history[0]!.thought_number ?? 1;\n\t\tconst end = history[history.length - 1]!.thought_number ?? history.length;\n\t\treturn [\n\t\t\t{\n\t\t\t\tpattern: 'no_alternatives_explored',\n\t\t\t\tseverity: 'warning',\n\t\t\t\tmessage: '5+ thoughts with no critique or branching — consider exploring alternatives',\n\t\t\t\tthought_range: [start, end],\n\t\t\t},\n\t\t];\n\t}\n\n\t/**\n\t * Detect runs of 4+ consecutive thoughts with the same thought_type.\n\t * Only fires when history has ≥5 thoughts and at least one explicitly set thought_type.\n\t */\n\tprivate _detectMonotonicType(history: ThoughtData[]): PatternSignal[] {\n\t\tif (history.length < 5) return [];\n\t\tconst hasExplicitType = history.some((t) => t.thought_type !== undefined);\n\t\tif (!hasExplicitType) return [];\n\n\t\tconst signals: PatternSignal[] = [];\n\t\tlet runType = history[0]!.thought_type ?? 'regular';\n\t\tlet runStart = 0;\n\t\tlet runLength = 1;\n\n\t\tfor (let i = 1; i < history.length; i++) {\n\t\t\tconst type = history[i]!.thought_type ?? 'regular';\n\t\t\tif (type === runType) {\n\t\t\t\trunLength++;\n\t\t\t} else {\n\t\t\t\tthis._flushMonotonicRun(history, runStart, runLength, runType, signals);\n\t\t\t\trunType = type;\n\t\t\t\trunStart = i;\n\t\t\t\trunLength = 1;\n\t\t\t}\n\t\t}\n\t\tthis._flushMonotonicRun(history, runStart, runLength, runType, signals);\n\t\treturn signals;\n\t}\n\n\t/** Emit a monotonic_type signal if the run length qualifies. */\n\tprivate _flushMonotonicRun(\n\t\thistory: ThoughtData[],\n\t\trunStart: number,\n\t\trunLength: number,\n\t\trunType: string,\n\t\tsignals: PatternSignal[]\n\t): void {\n\t\tif (runLength < 4) return;\n\t\tconst start = history[runStart]!.thought_number ?? runStart + 1;\n\t\tconst end = history[runStart + runLength - 1]!.thought_number ?? runStart + runLength;\n\t\tsignals.push({\n\t\t\tpattern: 'monotonic_type',\n\t\t\tseverity: 'warning',\n\t\t\tmessage: `4+ consecutive '${runType}' thoughts (${start}-${end}) — consider varying approach`,\n\t\t\tthought_range: [start, end],\n\t\t});\n\t}\n\n\t/** Detect runs of 3+ consecutive thoughts with strictly decreasing confidence. */\n\tprivate _detectConfidenceDrift(history: ThoughtData[]): PatternSignal[] {\n\t\tconst signals: PatternSignal[] = [];\n\t\tlet runStart = -1;\n\t\tlet runLength = 0;\n\t\tlet prevConf = -1;\n\n\t\tfor (let i = 0; i < history.length; i++) {\n\t\t\tconst conf = history[i]!.confidence;\n\t\t\tif (conf === undefined) {\n\t\t\t\tthis._flushDriftRun(history, runStart, runLength, signals);\n\t\t\t\trunStart = -1;\n\t\t\t\trunLength = 0;\n\t\t\t\tprevConf = -1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (runLength === 0) {\n\t\t\t\trunStart = i;\n\t\t\t\trunLength = 1;\n\t\t\t\tprevConf = conf;\n\t\t\t} else if (conf < prevConf) {\n\t\t\t\trunLength++;\n\t\t\t\tprevConf = conf;\n\t\t\t} else {\n\t\t\t\tthis._flushDriftRun(history, runStart, runLength, signals);\n\t\t\t\trunStart = i;\n\t\t\t\trunLength = 1;\n\t\t\t\tprevConf = conf;\n\t\t\t}\n\t\t}\n\t\tthis._flushDriftRun(history, runStart, runLength, signals);\n\t\treturn signals;\n\t}\n\n\t/** Emit a confidence_drift signal if the run length qualifies. */\n\tprivate _flushDriftRun(\n\t\thistory: ThoughtData[],\n\t\trunStart: number,\n\t\trunLength: number,\n\t\tsignals: PatternSignal[]\n\t): void {\n\t\tif (runLength < 3) return;\n\t\tconst start = history[runStart]!.thought_number ?? runStart + 1;\n\t\tconst end = history[runStart + runLength - 1]!.thought_number ?? runStart + runLength;\n\t\tconst firstConf = history[runStart]!.confidence!;\n\t\tconst lastConf = history[runStart + runLength - 1]!.confidence!;\n\t\tsignals.push({\n\t\t\tpattern: 'confidence_drift',\n\t\t\tseverity: 'warning',\n\t\t\tmessage: `Confidence decreasing across thoughts ${start}-${end} (${firstConf} → ${lastConf})`,\n\t\t\tthought_range: [start, end],\n\t\t});\n\t}\n\n\t/** Detect hypothesis verified within 3 subsequent thoughts — positive signal. */\n\tprivate _detectHealthyVerification(history: ThoughtData[]): PatternSignal[] {\n\t\tconst signals: PatternSignal[] = [];\n\t\tfor (let i = 0; i < history.length; i++) {\n\t\t\tif (history[i]!.thought_type !== 'hypothesis') continue;\n\t\t\tconst hypId = history[i]!.hypothesis_id;\n\t\t\tconst lookahead = history.slice(i + 1, i + 4);\n\t\t\tconst verifier = lookahead.find(\n\t\t\t\t(t) =>\n\t\t\t\t\tt.thought_type === 'verification' &&\n\t\t\t\t\t(t.hypothesis_id === hypId ||\n\t\t\t\t\t\tt.verification_target === (history[i]!.thought_number ?? i + 1))\n\t\t\t);\n\t\t\tif (verifier) {\n\t\t\t\tconst n = history[i]!.thought_number ?? i + 1;\n\t\t\t\tconst m = verifier.thought_number ?? history.indexOf(verifier) + 1;\n\t\t\t\tsignals.push({\n\t\t\t\t\tpattern: 'healthy_verification',\n\t\t\t\t\tseverity: 'info',\n\t\t\t\t\tmessage: `Hypothesis at thought ${n} verified at thought ${m} — good practice`,\n\t\t\t\t\tthought_range: [n, m],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn signals;\n\t}\n}\n"],"names":["PatternDetector","history","branches","signals","runStart","i","type","start","end","remaining","lookahead","hasVerification","t","n","Object","hasExplicitType","undefined","runType","runLength","prevConf","conf","firstConf","lastConf","hypId","verifier","m"],"mappings":"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"}
|
|
@@ -19,7 +19,13 @@ interface StructuralQualityResult {
|
|
|
19
19
|
type_diversity: number;
|
|
20
20
|
verification_coverage: number;
|
|
21
21
|
depth_efficiency: number;
|
|
22
|
-
confidence_stability: number;
|
|
22
|
+
confidence_stability: number | null;
|
|
23
|
+
};
|
|
24
|
+
raw_components: {
|
|
25
|
+
type_diversity: number;
|
|
26
|
+
verification_coverage: number;
|
|
27
|
+
depth_efficiency: number;
|
|
28
|
+
confidence_stability: number | null;
|
|
23
29
|
};
|
|
24
30
|
}
|
|
25
31
|
/**
|
|
@@ -30,6 +36,40 @@ interface StructuralQualityResult {
|
|
|
30
36
|
* Safe to register as singleton or transient in DI.
|
|
31
37
|
*/
|
|
32
38
|
export declare class SignalComputer {
|
|
39
|
+
/**
|
|
40
|
+
* Structural quality weight configuration.
|
|
41
|
+
*
|
|
42
|
+
* Weights reflect the relative importance of each quality dimension:
|
|
43
|
+
* - type_diversity (0.3): Shannon entropy of thought types — rewards reasoning that uses
|
|
44
|
+
* multiple cognitive modes (hypothesis, verification, critique, synthesis) rather than
|
|
45
|
+
* monotonic sequences. Based on information theory: higher entropy = more information.
|
|
46
|
+
*
|
|
47
|
+
* - verification_coverage (0.3): Ratio of verified to total hypotheses — rewards scientific
|
|
48
|
+
* rigor. Hypotheses without verification are speculation; verification grounds reasoning.
|
|
49
|
+
* Equal weight with diversity because unverified reasoning is a common failure mode.
|
|
50
|
+
*
|
|
51
|
+
* - depth_efficiency (0.2): Ratio of structural depth to total thoughts — rewards efficient
|
|
52
|
+
* reasoning. Deep chains (many revisions/branches) are good; but only if proportionally
|
|
53
|
+
* dense. Padding with low-value thoughts penalizes this metric.
|
|
54
|
+
*
|
|
55
|
+
* - confidence_stability (0.2): Low variance in self-assessed confidence — rewards calibrated
|
|
56
|
+
* reasoning. Wildly fluctuating confidence suggests uncertainty about the approach.
|
|
57
|
+
* Lower weight because confidence values are LLM self-reports (inherently noisy).
|
|
58
|
+
*
|
|
59
|
+
* Design rationale:
|
|
60
|
+
* - Diversity + Verification (0.6) > Depth + Stability (0.4): Structural properties of the
|
|
61
|
+
* reasoning DAG are more important than behavioral signals.
|
|
62
|
+
* - All weights are positive (no dimension is penalizing).
|
|
63
|
+
* - Weights sum to 1.0 for normalized scoring.
|
|
64
|
+
* - When confidence_stability is unavailable (n<2), remaining weights redistribute
|
|
65
|
+
* proportionally: td→0.375, vc→0.375, de→0.25 (preserving relative ratios).
|
|
66
|
+
*/
|
|
67
|
+
private static readonly QUALITY_WEIGHTS;
|
|
68
|
+
/**
|
|
69
|
+
* Redistributed weights when confidence_stability is excluded (n<2).
|
|
70
|
+
* Preserves relative ratios of remaining components (sum = 1.0).
|
|
71
|
+
*/
|
|
72
|
+
private static readonly QUALITY_WEIGHTS_NO_CS;
|
|
33
73
|
/**
|
|
34
74
|
* Compute confidence signals from history context.
|
|
35
75
|
*
|
|
@@ -45,20 +85,32 @@ export declare class SignalComputer {
|
|
|
45
85
|
* - `type_diversity` = Shannon entropy of thought_type distribution / log2(6)
|
|
46
86
|
* - `verification_coverage` = verified_hypotheses / max(total_hypotheses, 1) (1.0 if none)
|
|
47
87
|
* - `depth_efficiency` = max(chain_depth, branch_count + 1) / total_thoughts, clamped to 1.0
|
|
48
|
-
* - `confidence_stability` = 1 - stddev(confidences), default 0.5 when empty
|
|
88
|
+
* - `confidence_stability` = 1 - stddev(confidences), default 0.5 when empty, null when single value
|
|
49
89
|
* - `structural_quality` = td^0.3 * vc^0.3 * de^0.2 * cs^0.2 (weighted geometric mean)
|
|
50
90
|
*
|
|
91
|
+
* Note: When confidence_stability is null (fewer than 2 confidence values), it is
|
|
92
|
+
* excluded from the geometric mean and the remaining weights are redistributed
|
|
93
|
+
* proportionally (td→0.375, vc→0.375, de→0.25).
|
|
94
|
+
*
|
|
51
95
|
* @returns Score + components, or `null` when history is empty
|
|
52
96
|
*/
|
|
53
97
|
computeStructuralQuality(history: ThoughtData[], branches: Record<string, ThoughtData[]>, typeDistribution: Record<ThoughtType, number>, confidences: number[]): StructuralQualityResult | null;
|
|
54
98
|
/**
|
|
55
99
|
* Compute confidence stability: 1 - stddev(confidences).
|
|
56
100
|
*
|
|
57
|
-
* - Empty input → 0.5 (
|
|
58
|
-
* - Single value →
|
|
101
|
+
* - Empty input → 0.5 (neutral default)
|
|
102
|
+
* - Single value → null (insufficient data, excluded from structural quality)
|
|
59
103
|
* - Otherwise → max(1 - stddev, FLOOR)
|
|
60
104
|
*/
|
|
61
|
-
computeConfidenceStability(confidences: number[]): number;
|
|
105
|
+
computeConfidenceStability(confidences: number[]): number | null;
|
|
106
|
+
/**
|
|
107
|
+
* Compute raw (unfloored) confidence stability: 1 - stddev(confidences).
|
|
108
|
+
*
|
|
109
|
+
* - Empty input → 0.5 (neutral default)
|
|
110
|
+
* - Single value → null (insufficient data)
|
|
111
|
+
* - Otherwise → 1 - stddev (may be below FLOOR)
|
|
112
|
+
*/
|
|
113
|
+
computeRawConfidenceStability(confidences: number[]): number | null;
|
|
62
114
|
}
|
|
63
115
|
export {};
|
|
64
116
|
//# sourceMappingURL=SignalComputer.d.ts.map
|