tracelattice 1.3.2 → 1.3.3
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 +25 -25
- package/dist/ServerConfig.d.ts +2 -23
- package/dist/ServerConfig.d.ts.map +1 -1
- package/dist/ServerConfig.js.map +1 -1
- package/dist/__tests__/eval/fixtures/scenarios.d.ts.map +1 -1
- package/dist/__tests__/helpers/factories.d.ts +13 -1
- package/dist/__tests__/helpers/factories.d.ts.map +1 -1
- package/dist/cache/DiscoveryCache.d.ts +1 -1
- package/dist/cache/DiscoveryCache.d.ts.map +1 -1
- package/dist/cache/DiscoveryCache.js.map +1 -1
- package/dist/cli.js +3483 -8
- package/dist/config/ConfigLoader.d.ts +2 -2
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +6 -4
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -0
- package/dist/contracts/features.d.ts +39 -0
- package/dist/contracts/features.d.ts.map +1 -0
- package/dist/contracts/features.js +15 -0
- package/dist/contracts/features.js.map +1 -0
- package/dist/contracts/ids.d.ts +58 -0
- package/dist/contracts/ids.d.ts.map +1 -0
- package/dist/contracts/ids.js +31 -0
- package/dist/contracts/ids.js.map +1 -0
- package/dist/contracts/interfaces.d.ts +6 -3
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/strategy.d.ts +2 -2
- package/dist/contracts/strategy.d.ts.map +1 -1
- package/dist/contracts/suspension.d.ts +3 -2
- package/dist/contracts/suspension.d.ts.map +1 -1
- package/dist/contracts/transport.d.ts +25 -0
- package/dist/contracts/transport.d.ts.map +1 -0
- package/dist/core/HistoryManager.d.ts +2 -3
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +10 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/IThoughtFormatter.d.ts +51 -0
- package/dist/core/IThoughtFormatter.d.ts.map +1 -0
- package/dist/core/IThoughtFormatter.js +1 -0
- package/dist/core/InputNormalizer.d.ts.map +1 -1
- package/dist/core/InputNormalizer.js +4 -3
- package/dist/core/InputNormalizer.js.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +1 -1
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/ThoughtFormatter.d.ts +2 -1
- package/dist/core/ThoughtFormatter.d.ts.map +1 -1
- package/dist/core/ThoughtFormatter.js +3 -0
- package/dist/core/ThoughtFormatter.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts +2 -2
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +8 -3
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/compression/CompressionService.js +3 -3
- package/dist/core/compression/CompressionService.js.map +1 -1
- package/dist/core/compression/Summary.d.ts +4 -3
- package/dist/core/compression/Summary.d.ts.map +1 -1
- package/dist/core/graph/Edge.d.ts +11 -4
- package/dist/core/graph/Edge.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +5 -5
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.d.ts +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.js.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +5 -0
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/core/reasoning.d.ts +8 -1
- package/dist/core/reasoning.d.ts.map +1 -1
- package/dist/core/step.d.ts +5 -0
- package/dist/core/step.d.ts.map +1 -1
- package/dist/core/thought.d.ts +4 -3
- package/dist/core/thought.d.ts.map +1 -1
- package/dist/core/tools/InMemorySuspensionStore.d.ts +3 -1
- package/dist/core/tools/InMemorySuspensionStore.d.ts.map +1 -1
- package/dist/core/tools/InMemorySuspensionStore.js +2 -2
- package/dist/core/tools/InMemorySuspensionStore.js.map +1 -1
- package/dist/di/Container.d.ts +6 -3
- package/dist/di/Container.d.ts.map +1 -1
- package/dist/di/Container.js.map +1 -1
- package/dist/di/ServiceRegistry.d.ts +3 -3
- package/dist/di/ServiceRegistry.d.ts.map +1 -1
- package/dist/errors.d.ts +36 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +49 -22
- package/dist/errors.js.map +1 -1
- package/dist/health/HealthChecker.d.ts +1 -1
- package/dist/health/HealthChecker.d.ts.map +1 -1
- package/dist/health/HealthChecker.js.map +1 -1
- package/dist/lib.d.ts +60 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +2 -2
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +1 -1
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceFactory.d.ts +1 -1
- package/dist/persistence/PersistenceFactory.d.ts.map +1 -1
- package/dist/persistence/PersistenceFactory.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +1 -1
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts +11 -13
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/pool/IConnectionPool.d.ts +100 -0
- package/dist/pool/IConnectionPool.d.ts.map +1 -0
- package/dist/pool/IConnectionPool.js +1 -0
- package/dist/registry/BaseRegistry.d.ts +1 -1
- package/dist/registry/BaseRegistry.d.ts.map +1 -1
- package/dist/registry/BaseRegistry.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js.map +1 -1
- package/dist/transport/BaseTransport.d.ts +3 -2
- package/dist/transport/BaseTransport.d.ts.map +1 -1
- package/dist/transport/BaseTransport.js +1 -1
- package/dist/transport/BaseTransport.js.map +1 -1
- package/dist/transport/HttpTransport.d.ts +4 -2
- package/dist/transport/HttpTransport.d.ts.map +1 -1
- package/dist/transport/HttpTransport.js +4 -1
- package/dist/transport/HttpTransport.js.map +1 -1
- package/dist/transport/SseTransport.d.ts +4 -2
- package/dist/transport/SseTransport.d.ts.map +1 -1
- package/dist/transport/SseTransport.js +3 -0
- package/dist/transport/SseTransport.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +4 -2
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +4 -1
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/dist/types/skill.d.ts +5 -0
- package/dist/types/skill.d.ts.map +1 -1
- package/dist/types/tool.d.ts +5 -0
- package/dist/types/tool.d.ts.map +1 -1
- package/package.json +11 -11
- package/dist/__tests__/helpers/index.d.ts +0 -3
- package/dist/__tests__/helpers/index.d.ts.map +0 -1
- package/dist/contracts/index.d.ts +0 -14
- package/dist/contracts/index.d.ts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1
- package/dist/persistence/PersistenceBackend.d.ts.map +0 -1
- /package/dist/{persistence → contracts}/PersistenceBackend.d.ts +0 -0
- /package/dist/{persistence → contracts}/PersistenceBackend.js +0 -0
- /package/dist/contracts/{index.js → transport.js} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NullLogger } from "../logger/NullLogger.js";
|
|
2
|
+
import { GLOBAL_SESSION_ID, asSessionId } from "../contracts/ids.js";
|
|
2
3
|
import { InvalidBacktrackError, InvalidToolCallError, SuspensionExpiredError, SuspensionNotFoundError, ValidationError, getErrorMessage } from "../errors.js";
|
|
3
4
|
import { GraphView } from "./graph/GraphView.js";
|
|
4
5
|
import { normalizeInput } from "./InputNormalizer.js";
|
|
@@ -193,8 +194,7 @@ class ThoughtProcessor {
|
|
|
193
194
|
return firstId;
|
|
194
195
|
}
|
|
195
196
|
_getEdgeStore() {
|
|
196
|
-
|
|
197
|
-
return 'function' == typeof hm.getEdgeStore ? hm.getEdgeStore() : void 0;
|
|
197
|
+
return this.historyManager.getEdgeStore();
|
|
198
198
|
}
|
|
199
199
|
validateInput(input) {
|
|
200
200
|
const warnings = [];
|
|
@@ -311,12 +311,17 @@ class ThoughtProcessor {
|
|
|
311
311
|
return 'hypothesis';
|
|
312
312
|
case 'backtrack':
|
|
313
313
|
return 'regular';
|
|
314
|
+
default:
|
|
315
|
+
{
|
|
316
|
+
const _exhaust = t;
|
|
317
|
+
throw new Error(`Unhandled type: ${_exhaust}`);
|
|
318
|
+
}
|
|
314
319
|
}
|
|
315
320
|
}
|
|
316
321
|
_handleToolCall(input, sessionId) {
|
|
317
322
|
this.historyManager.addThought(input);
|
|
318
323
|
const record = this._suspensionStore.suspend({
|
|
319
|
-
sessionId: sessionId
|
|
324
|
+
sessionId: sessionId ? asSessionId(sessionId) : GLOBAL_SESSION_ID,
|
|
320
325
|
toolCallThoughtNumber: input.thought_number,
|
|
321
326
|
toolName: input.tool_name,
|
|
322
327
|
toolArguments: input.tool_arguments ?? {},
|
|
@@ -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: 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":";;;;;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;IAMA,OAAwB,iBAAmD;QAC1E,kBAAkB;QAClB,uBAAuB;QACvB,0BAA0B;QAC1B,kCAAkC;IACnC,EAAE;IAcM,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;QAGpCA,SAAS,IAAI,CAAC,CAACE,GAAGC;YACjB,MAAMC,KAAKrB,iBAAiB,cAAc,CAACmB,EAAE,OAAO,CAAC,IAAI;YACzD,MAAMG,KAAKtB,iBAAiB,cAAc,CAACoB,EAAE,OAAO,CAAC,IAAI;YACzD,OAAOC,KAAKC;QACb;QAEA,MAAMC,aAAaP,aAAa;QAChC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAACO,aAC5B,IAAI,CAAC,cAAc,CAAC,GAAG,CAACA,YAAY,IAAItB;QAEzC,MAAMuB,YAAY,IAAI,CAAC,cAAc,CAAC,GAAG,CAACD;QAE1C,MAAME,QAAkB,EAAE;QAC1B,KAAK,MAAMC,WAAWT,SAAU;YAC/B,IAAIQ,MAAM,MAAM,IAAI,GAAG;YAEvB,MAAME,YAAYH,UAAU,GAAG,CAACE,QAAQ,OAAO;YAC/C,IAAIC,AAAcC,WAAdD,cAA2BZ,CAAAA,uBAAuBY,YAAY;gBAIlEF,MAAM,IAAI,CAACC,QAAQ,OAAO;gBAC1BF,UAAU,GAAG,CAACE,QAAQ,OAAO,EAAEX;;QAChC;QAEA,OAAOU;IACR;IA2CA,MAAa,QAAQI,KAAkB,EAA2B;QACjE,IAAI;YAEH,MAAMC,kBAAkBC,eAAeF;YACvC,MAAMb,YAAYc,gBAAgB,UAAU;YAG5C,IAAIA,gBAAgB,WAAW,EAAE;gBAChC,IAAI,CAAC,cAAc,CAAC,KAAK,CAACd;gBAC1B,IAAI,CAAC,GAAG,CAAC,2BAA2B;oBAAE,WAAWA,aAAa;gBAAa;YAC5E;YAIA,IAAI,CAACc,gBAAgB,mBAAmB,EACvCA,gBAAgB,mBAAmB,GAAG,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAACd;YAEhF,IAAI,CAACc,gBAAgB,gBAAgB,EACpCA,gBAAgB,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,kBAAkB,CAACd;YAG3E,MAAM,EAAE,QAAQgB,cAAc,EAAE,UAAUC,gBAAgB,EAAE,GAC3D,IAAI,CAAC,aAAa,CAACH;YACpB,MAAM,EAAE,QAAQI,YAAY,EAAE,UAAUC,WAAW,EAAE,GACpD,IAAI,CAAC,wBAAwB,CAACH,gBAAgBhB;YAC/C,MAAMoB,cAAc;mBAAIH;mBAAqBE;aAAY;YAGzD,IAAI,CAAC,iBAAiB,CAACD,cAAclB;YAIrC,IAAIkB,AAA8B,gBAA9BA,aAAa,YAAY,IAAoB,IAAI,CAAC,gBAAgB,EACrE,OAAO,IAAI,CAAC,eAAe,CAACA,cAAclB;YAK3C,IAAIkB,AAA8B,uBAA9BA,aAAa,YAAY,IAA2B,IAAI,CAAC,gBAAgB,EAC5E,IAAI,CAAC,sBAAsB,CAACA,cAAclB;YAG3C,IAAI,CAAC,cAAc,CAAC,UAAU,CAACkB;YAE/B,MAAMG,mBAAmB,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAACH;YAC7D,IAAI,CAAC,GAAG,CAACG,kBAAkB;gBAAE,WAAWrB,aAAa;YAAa;YAGlE,MAAMsB,UAAU,IAAI,CAAC,cAAc,CAAC,UAAU,CAACtB;YAC/C,MAAMuB,WAAW,IAAI,CAAC,cAAc,CAAC,WAAW,CAACvB;YAEjD,MAAMwB,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,EAC3BlB;YAKD,MAAM4B,WAAW,IAAI,CAAC,YAAY,CAACV,cAAcI,SAASG,gBAAgBzB;YAE1E,OAAO;gBACN,SAAS;oBACR;wBACC,MAAM;wBACN,MAAM6B,KAAK,SAAS,CACnB;4BACA,gBAAgBX,aAAa,cAAc;4BAC3C,gBAAgBA,aAAa,cAAc;4BAC3C,qBAAqBA,aAAa,mBAAmB,IAAI;4BACzD,UAAU,IAAI,CAAC,cAAc,CAAC,YAAY,CAAClB;4BAC3C,wBAAwB,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAACA;4BAC7D,qBAAqBkB,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,YAAY,KAAK,CAAC,GAAG;4BAAG,CAAC;4BACnE,GAAIpB,YAAY;gCAAE,YAAYA;4BAAU,IAAI,CAAC,CAAC;wBAC/C,GACA,MACA;oBAED;iBACA;YACF;QACD,EAAE,OAAO8B,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,EAC5DjC,SAAkB,EACC;QACnB,IAAI4B;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,WAAW5B,aAAa;gBACxBsB;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,MAAMrC,aAAa;YACzB,MAAMsC,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,gBAAgB5B,SAAiB,EAAEwC,QAAgB,EAAsB;QAChF,MAAMN,YAAY,IAAI,CAAC,aAAa;QACpC,MAAMX,WAAW,IAAI,CAAC,cAAc,CAAC,WAAW,CAACvB;QACjD,MAAMyC,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,CAACnC,WAAW0C;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,MAAMZ,WAAqB,EAAE;QAC7B,IAAIY,MAAM,cAAc,GAAGA,MAAM,cAAc,EAAE;YAChD,MAAMgC,gBAAgBhC,MAAM,cAAc;YAC1CZ,SAAS,IAAI,CACZ,CAAC,kCAAkC,EAAE4C,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;YAAOZ;QAAS;IAClC;IAmBQ,yBAAyBY,KAAkB,EAAEb,SAAkB,EAGrE;QACD,MAAMC,WAAqB,EAAE;QAC7B,MAAM6C,gBAAgB,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC9C;QAG3D,IAAIa,AAA8BD,WAA9BC,MAAM,mBAAmB,IAAkBA,MAAM,mBAAmB,GAAGiC,eAAe;YACzF7C,SAAS,IAAI,CACZ,CAAC,sCAAsC,EAAEY,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;YACjF7C,SAAS,IAAI,CACZ,CAAC,kCAAkC,EAAEY,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;YACzF7C,SAAS,IAAI,CACZ,CAAC,sCAAsC,EAAEY,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,MAAMkC,QAAQlC,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAACmC,IAAcA,KAAKF;YACjE,IAAIC,MAAM,MAAM,GAAGlC,MAAM,iBAAiB,CAAC,MAAM,EAAE;gBAClD,MAAMoC,UAAUpC,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAACmC,IAAcA,IAAIF;gBAClE7C,SAAS,IAAI,CACZ,CAAC,sCAAsC,EAAEgD,QAAQ,IAAI,CAAC,MAAM,eAAe,EAAEH,cAAc,UAAU,CAAC;gBAEvG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,uCAAuC;oBACxD,UAAUjC,MAAM,iBAAiB;oBACjC,UAAUkC;oBACVD;gBACD;YACD;YACAjC,MAAM,iBAAiB,GAAGkC,MAAM,MAAM,GAAG,IAAIA,QAAQnC;QACtD;QAGA,IAAIC,MAAM,mBAAmB,EAAE,QAAQ;YACtC,MAAMkC,QAAQlC,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAACmC,IAAcA,KAAKF;YACnE,IAAIC,MAAM,MAAM,GAAGlC,MAAM,mBAAmB,CAAC,MAAM,EAAE;gBACpD,MAAMoC,UAAUpC,MAAM,mBAAmB,CAAC,MAAM,CAC/C,CAACmC,IAAcA,IAAIF;gBAEpB7C,SAAS,IAAI,CACZ,CAAC,wCAAwC,EAAEgD,QAAQ,IAAI,CAAC,MAAM,eAAe,EAAEH,cAAc,UAAU,CAAC;gBAEzG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,yCAAyC;oBAC1D,UAAUjC,MAAM,mBAAmB;oBACnC,UAAUkC;oBACVD;gBACD;YACD;YACAjC,MAAM,mBAAmB,GAAGkC,MAAM,MAAM,GAAG,IAAIA,QAAQnC;QACxD;QAGA,IAAIC,MAAM,gBAAgB,EAAE,QAAQ;YACnC,MAAMkC,QAAQlC,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAACqC,KAC5C,IAAI,CAAC,cAAc,CAAC,YAAY,CAAClD,WAAWkD;YAE7C,IAAIH,MAAM,MAAM,GAAGlC,MAAM,gBAAgB,CAAC,MAAM,EAAE;gBACjD,MAAMoC,UAAUpC,MAAM,gBAAgB,CAAC,MAAM,CAC5C,CAACqC,KAAe,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAClD,WAAWkD;gBAE9DjD,SAAS,IAAI,CAAC,CAAC,qCAAqC,EAAEgD,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC3E,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,sCAAsC;oBACvD,UAAUpC,MAAM,gBAAgB;oBAChC,UAAUkC;oBACV,kBAAkB,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC/C;gBACpD;YACD;YACAa,MAAM,gBAAgB,GAAGkC,MAAM,MAAM,GAAG,IAAIA,QAAQnC;QACrD;QAEA,OAAO;YAAE,QAAQC;YAAOZ;QAAS;IAClC;IAMQ,kBAAkBY,KAAkB,EAAEb,SAAkB,EAAQ;QACvE,MAAMmD,IAAItC,MAAM,YAAY;QAC5B,IAAKsC,AAAAA,CAAAA,AAAM,gBAANA,KAAqBA,AAAM,uBAANA,CAAuB,KAAM,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,EACpF,MAAM,IAAIC,gBACT,gBACA,CAAC,MAAM,EAAED,EAAE,wGAAwG,CAAC;QAGtH,IACEA,AAAAA,CAAAA,AAAM,iBAANA,KAAsBA,AAAM,oBAANA,KAAyBA,AAAM,gBAANA,CAAgB,KAChE,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,EAE/B,MAAM,IAAIC,gBACT,gBACA,CAAC,MAAM,EAAED,EAAE,oHAAoH,EAAEnE,iBAAiB,kBAAkB,CAACmE,GAAG,uBAAuB,CAAC;QAGlM,IAAIA,AAAM,gBAANA,KAAqB,CAACtC,MAAM,SAAS,EACxC,MAAM,IAAIwC,qBACT,uBAAuBxC,MAAM,cAAc,GAAG;QAGhD,IAAIsC,AAAM,uBAANA,KAA4B,CAACtC,MAAM,kBAAkB,EACxD,MAAM,IAAIuC,gBACT,sBACA,8BAA8BvC,MAAM,cAAc,GAAG;QAGvD,IAAIsC,AAAM,gBAANA,GAAmB;YACtB,IAAItC,AAA2BD,WAA3BC,MAAM,gBAAgB,EACzB,MAAM,IAAIuC,gBACT,oBACA,uBAAuBvC,MAAM,cAAc,GAAG;YAGhD,IAAIA,MAAM,gBAAgB,GAAGA,MAAM,cAAc,EAChD,MAAM,IAAIyC,sBACT,sBAAsBzC,MAAM,gBAAgB,GAAG,gCAAgCA,MAAM,cAAc;YAGrG,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAACA,MAAM,gBAAgB,EAAEb,YACtD,MAAM,IAAIsD,sBACT,sBAAsBzC,MAAM,gBAAgB,GAAG;QAGlD;IACD;IAMQ,qBAAqB0C,aAAqB,EAAEvD,SAAkB,EAAW;QAChF,MAAMsB,UAAU,IAAI,CAAC,cAAc,CAAC,UAAU,CAACtB;QAC/C,KAAK,MAAMmD,KAAK7B,QACf,IAAI6B,EAAE,cAAc,KAAKI,eAAe,OAAO;QAEhD,MAAMhC,WAAW,IAAI,CAAC,cAAc,CAAC,WAAW,CAACvB;QACjD,KAAK,MAAMwD,kBAAkBC,OAAO,MAAM,CAAClC,UAC1C,KAAK,MAAM4B,KAAKK,eACf,IAAIL,EAAE,cAAc,KAAKI,eAAe,OAAO;QAGjD,OAAO;IACR;IAMA,OAAe,mBAAmBJ,CAA+C,EAAU;QAC1F,OAAQA;YACP,KAAK;gBACJ,OAAO;YACR,KAAK;gBACJ,OAAO;YACR,KAAK;gBACJ,OAAO;QACT;IACD;IAOQ,gBAAgBtC,KAAkB,EAAEb,SAAkB,EAAkB;QAC/E,IAAI,CAAC,cAAc,CAAC,UAAU,CAACa;QAC/B,MAAM6C,SAA2B,IAAI,CAAC,gBAAgB,CAAE,OAAO,CAAC;YAC/D,WAAW1D,aAAa;YACxB,uBAAuBa,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,GAAIb,YAAY;4BAAE,YAAYA;wBAAU,IAAI,CAAC,CAAC;oBAC/C,GACA,MACA;gBAEF;aACA;QACF;IACD;IAOQ,uBAAuBa,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 { asSessionId, GLOBAL_SESSION_ID } from '../contracts/ids.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 '../contracts/features.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;\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/** Access the EdgeStore via IHistoryManager. @private */\n\tprivate _getEdgeStore(): IEdgeStore | undefined {\n\t\treturn this.historyManager.getEdgeStore();\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\tdefault: {\n\t\t\t\tconst _exhaust: never = t;\n\t\t\t\tthrow new Error(`Unhandled type: ${_exhaust as string}`);\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 ? asSessionId(sessionId) : GLOBAL_SESSION_ID,\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","originalTotal","historyLength","valid","n","dropped","id","t","ValidationError","InvalidToolCallError","InvalidBacktrackError","thoughtNumber","branchThoughts","Object","_exhaust","Error","record","asSessionId","GLOBAL_SESSION_ID","_sessionId","token","peeked","Date","SuspensionExpiredError","SuspensionNotFoundError"],"mappings":"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"}
|
|
@@ -60,10 +60,10 @@ class CompressionService {
|
|
|
60
60
|
const thoughts = this._lookupThoughts(sessionId, coveredIds);
|
|
61
61
|
const summary = {
|
|
62
62
|
id: generateUlid(),
|
|
63
|
-
sessionId,
|
|
63
|
+
sessionId: sessionId,
|
|
64
64
|
branchId,
|
|
65
|
-
rootThoughtId,
|
|
66
|
-
coveredIds,
|
|
65
|
+
rootThoughtId: rootThoughtId,
|
|
66
|
+
coveredIds: coveredIds,
|
|
67
67
|
coveredRange: this._coveredRange(thoughts),
|
|
68
68
|
topics: this._extractTopics(thoughts),
|
|
69
69
|
aggregateConfidence: this._meanConfidence(thoughts),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/compression/CompressionService.js","sources":["../../../src/core/compression/CompressionService.ts"],"sourcesContent":["/**\n * CompressionService — deterministic branch summarization.\n *\n * Compresses a terminated branch (or any subtree rooted at a thought) into a\n * single {@link Summary} record. Pure offline computation: no LLM, no I/O.\n *\n * Topic extraction is unigram frequency with stopword filtering; aggregate\n * confidence is the arithmetic mean of per-thought calibrated (or raw)\n * confidence values. The covered set is identified via\n * {@link GraphView.descendants}. Compression is **additive**: original\n * thoughts are never mutated or deleted.\n *\n * @module core/compression/CompressionService\n */\n\nimport type { ISummaryStore, Summary } from '../../contracts/summary.js';\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport type { IHistoryManager } from '../IHistoryManager.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ConfidenceSignals } from '../reasoning.js';\nimport { GraphView } from '../graph/GraphView.js';\nimport { generateUlid } from '../ids.js';\n\n/** Stopwords excluded from topic extraction (lowercase). */\nconst STOPWORDS: ReadonlySet<string> = new Set([\n\t'the', 'this', 'that', 'then', 'than', 'with', 'from', 'have', 'will', 'been',\n\t'they', 'them', 'their', 'there', 'about', 'would', 'could', 'should', 'which',\n\t'where', 'when', 'what', 'some', 'into', 'also', 'just', 'like', 'over', 'such',\n\t'after', 'only', 'most', 'very', 'much', 'well', 'even', 'still', 'since',\n\t'being', 'doing', 'going', 'using',\n]);\n\nconst MIN_TOKEN_LENGTH = 4;\nconst TOP_TOPICS = 3;\n\n/** Local view of {@link ThoughtData} that exposes optional confidence signals. */\ntype ThoughtWithSignals = ThoughtData & { readonly confidence_signals?: ConfidenceSignals };\n\n/** Dependencies required by {@link CompressionService}. */\nexport interface CompressionDeps {\n\treadonly historyManager: IHistoryManager;\n\treadonly edgeStore: IEdgeStore;\n\treadonly summaryStore: ISummaryStore;\n\treadonly logger?: Logger;\n}\n\n/**\n * Deterministic, offline compression of branch subtrees into {@link Summary}.\n *\n * @example\n * ```typescript\n * const svc = new CompressionService({ historyManager, edgeStore, summaryStore });\n * const summary = svc.compressBranch('s1', 'alt-1', 'thought-root');\n * ```\n */\nexport class CompressionService {\n\tprivate readonly _deps: CompressionDeps;\n\tprivate readonly _graph: GraphView;\n\n\tconstructor(deps: CompressionDeps) {\n\t\tthis._deps = deps;\n\t\tthis._graph = new GraphView(deps.edgeStore);\n\t}\n\n\t/**\n\t * Compress the subtree rooted at `rootThoughtId` into a {@link Summary}.\n\t *\n\t * Idempotency: if a summary for the same `(branchId, rootThoughtId)` already\n\t * exists in the store, the existing summary is returned unchanged — same\n\t * inputs always yield the same Summary identity.\n\t */\n\tcompressBranch(sessionId: string, branchId: string, rootThoughtId: string): Summary {\n\t\tconst existing = this._findExistingForRoot(sessionId, branchId, rootThoughtId);\n\t\tif (existing) return existing;\n\n\t\tconst coveredIds = this._collectCovered(sessionId, rootThoughtId);\n\t\tconst thoughts = this._lookupThoughts(sessionId, coveredIds);\n\t\tconst summary: Summary = {\n\t\t\tid: generateUlid(),\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcoveredIds,\n\t\t\tcoveredRange: this._coveredRange(thoughts),\n\t\t\ttopics: this._extractTopics(thoughts),\n\t\t\taggregateConfidence: this._meanConfidence(thoughts),\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\n\t\tthis._deps.summaryStore.add(summary);\n\t\tthis._deps.logger?.debug('compression.branch.compressed', {\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcovered: coveredIds.length,\n\t\t\ttopics: summary.topics,\n\t\t});\n\t\treturn summary;\n\t}\n\n\t/** Look up an existing summary on this branch with a matching root. */\n\tprivate _findExistingForRoot(\n\t\tsessionId: string,\n\t\tbranchId: string,\n\t\trootThoughtId: string\n\t): Summary | undefined {\n\t\tfor (const s of this._deps.summaryStore.forBranch(sessionId, branchId)) {\n\t\t\tif (s.rootThoughtId === rootThoughtId) return s;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Collect the root and all of its descendants (chronological BFS). */\n\tprivate _collectCovered(sessionId: string, rootThoughtId: string): readonly string[] {\n\t\tconst descendants = this._graph.descendants(sessionId, rootThoughtId);\n\t\treturn [rootThoughtId, ...descendants];\n\t}\n\n\t/**\n\t * Resolve covered ids to {@link ThoughtData}, dropping any not found in\n\t * the history (defensive — graph may reference evicted thoughts).\n\t */\n\tprivate _lookupThoughts(sessionId: string, coveredIds: readonly string[]): ThoughtData[] {\n\t\tconst history = this._deps.historyManager.getHistory(sessionId);\n\t\tconst byId = new Map<string, ThoughtData>();\n\t\tfor (const t of history) {\n\t\t\tif (t.id !== undefined) byId.set(t.id, t);\n\t\t}\n\t\tconst out: ThoughtData[] = [];\n\t\tfor (const id of coveredIds) {\n\t\t\tconst t = byId.get(id);\n\t\t\tif (t) out.push(t);\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * Mean of (`calibrated_confidence` ?? `confidence` ?? 0) across covered.\n\t * Returns 0 when no thoughts are covered.\n\t */\n\tprivate _meanConfidence(thoughts: readonly ThoughtData[]): number {\n\t\tif (thoughts.length === 0) return 0;\n\t\tlet sum = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tconst withSignals = t as ThoughtWithSignals;\n\t\t\tconst calibrated = withSignals.confidence_signals?.calibrated_confidence;\n\t\t\tsum += calibrated ?? t.confidence ?? 0;\n\t\t}\n\t\treturn sum / thoughts.length;\n\t}\n\n\t/**\n\t * Inclusive `[min, max]` of `thought_number` across covered thoughts.\n\t * Returns `[0, 0]` when no thoughts are covered.\n\t */\n\tprivate _coveredRange(thoughts: readonly ThoughtData[]): readonly [number, number] {\n\t\tif (thoughts.length === 0) return [0, 0];\n\t\tlet min = Number.POSITIVE_INFINITY;\n\t\tlet max = Number.NEGATIVE_INFINITY;\n\t\tfor (const t of thoughts) {\n\t\t\tconst n = t.thought_number;\n\t\t\tif (n < min) min = n;\n\t\t\tif (n > max) max = n;\n\t\t}\n\t\treturn [min, max];\n\t}\n\n\t/**\n\t * Extract top-3 unigrams by frequency from concatenated thought text.\n\t * Ties broken by first-occurrence order (stable).\n\t */\n\tprivate _extractTopics(thoughts: readonly ThoughtData[]): readonly string[] {\n\t\tif (thoughts.length === 0) return [];\n\t\tconst counts = new Map<string, number>();\n\t\tconst order = new Map<string, number>();\n\t\tlet position = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tfor (const raw of (t.thought ?? '').split(/\\s+/)) {\n\t\t\t\tconst token = this._normalizeToken(raw);\n\t\t\t\tif (token === null) continue;\n\t\t\t\tif (!counts.has(token)) order.set(token, position++);\n\t\t\t\tcounts.set(token, (counts.get(token) ?? 0) + 1);\n\t\t\t}\n\t\t}\n\t\tif (counts.size === 0) return [];\n\t\tconst entries = Array.from(counts.entries());\n\t\tentries.sort((a, b) => {\n\t\t\tif (b[1] !== a[1]) return b[1] - a[1];\n\t\t\treturn (order.get(a[0]) ?? 0) - (order.get(b[0]) ?? 0);\n\t\t});\n\t\treturn entries.slice(0, TOP_TOPICS).map(([word]) => word);\n\t}\n\n\t/** Lowercase + strip non-alphanumerics; reject if too short or a stopword. */\n\tprivate _normalizeToken(raw: string): string | null {\n\t\tconst cleaned = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');\n\t\tif (cleaned.length < MIN_TOKEN_LENGTH) return null;\n\t\tif (STOPWORDS.has(cleaned)) return null;\n\t\treturn cleaned;\n\t}\n}\n"],"names":["STOPWORDS","Set","MIN_TOKEN_LENGTH","TOP_TOPICS","CompressionService","deps","GraphView","sessionId","branchId","rootThoughtId","existing","coveredIds","thoughts","summary","generateUlid","Date","s","descendants","history","byId","Map","t","undefined","out","id","sum","withSignals","calibrated","min","Number","max","n","counts","order","position","raw","token","entries","Array","a","b","word","cleaned"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core/compression/CompressionService.js","sources":["../../../src/core/compression/CompressionService.ts"],"sourcesContent":["/**\n * CompressionService — deterministic branch summarization.\n *\n * Compresses a terminated branch (or any subtree rooted at a thought) into a\n * single {@link Summary} record. Pure offline computation: no LLM, no I/O.\n *\n * Topic extraction is unigram frequency with stopword filtering; aggregate\n * confidence is the arithmetic mean of per-thought calibrated (or raw)\n * confidence values. The covered set is identified via\n * {@link GraphView.descendants}. Compression is **additive**: original\n * thoughts are never mutated or deleted.\n *\n * @module core/compression/CompressionService\n */\n\nimport type { ISummaryStore, Summary } from '../../contracts/summary.js';\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport type { IHistoryManager } from '../IHistoryManager.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ConfidenceSignals } from '../reasoning.js';\nimport { GraphView } from '../graph/GraphView.js';\nimport { generateUlid } from '../ids.js';\n\n/** Stopwords excluded from topic extraction (lowercase). */\nconst STOPWORDS: ReadonlySet<string> = new Set([\n\t'the', 'this', 'that', 'then', 'than', 'with', 'from', 'have', 'will', 'been',\n\t'they', 'them', 'their', 'there', 'about', 'would', 'could', 'should', 'which',\n\t'where', 'when', 'what', 'some', 'into', 'also', 'just', 'like', 'over', 'such',\n\t'after', 'only', 'most', 'very', 'much', 'well', 'even', 'still', 'since',\n\t'being', 'doing', 'going', 'using',\n]);\n\nconst MIN_TOKEN_LENGTH = 4;\nconst TOP_TOPICS = 3;\n\n/** Local view of {@link ThoughtData} that exposes optional confidence signals. */\ntype ThoughtWithSignals = ThoughtData & { readonly confidence_signals?: ConfidenceSignals };\n\n/** Dependencies required by {@link CompressionService}. */\nexport interface CompressionDeps {\n\treadonly historyManager: IHistoryManager;\n\treadonly edgeStore: IEdgeStore;\n\treadonly summaryStore: ISummaryStore;\n\treadonly logger?: Logger;\n}\n\n/**\n * Deterministic, offline compression of branch subtrees into {@link Summary}.\n *\n * @example\n * ```typescript\n * const svc = new CompressionService({ historyManager, edgeStore, summaryStore });\n * const summary = svc.compressBranch('s1', 'alt-1', 'thought-root');\n * ```\n */\nexport class CompressionService {\n\tprivate readonly _deps: CompressionDeps;\n\tprivate readonly _graph: GraphView;\n\n\tconstructor(deps: CompressionDeps) {\n\t\tthis._deps = deps;\n\t\tthis._graph = new GraphView(deps.edgeStore);\n\t}\n\n\t/**\n\t * Compress the subtree rooted at `rootThoughtId` into a {@link Summary}.\n\t *\n\t * Idempotency: if a summary for the same `(branchId, rootThoughtId)` already\n\t * exists in the store, the existing summary is returned unchanged — same\n\t * inputs always yield the same Summary identity.\n\t */\n\tcompressBranch(sessionId: string, branchId: string, rootThoughtId: string): Summary {\n\t\tconst existing = this._findExistingForRoot(sessionId, branchId, rootThoughtId);\n\t\tif (existing) return existing;\n\n\t\tconst coveredIds = this._collectCovered(sessionId, rootThoughtId);\n\t\tconst thoughts = this._lookupThoughts(sessionId, coveredIds);\n\t\tconst summary: Summary = {\n\t\t\tid: generateUlid(),\n\t\t\tsessionId: sessionId as Summary['sessionId'],\n\t\t\tbranchId,\n\t\t\trootThoughtId: rootThoughtId as Summary['rootThoughtId'],\n\t\t\tcoveredIds: coveredIds as Summary['coveredIds'],\n\t\t\tcoveredRange: this._coveredRange(thoughts),\n\t\t\ttopics: this._extractTopics(thoughts),\n\t\t\taggregateConfidence: this._meanConfidence(thoughts),\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\n\t\tthis._deps.summaryStore.add(summary);\n\t\tthis._deps.logger?.debug('compression.branch.compressed', {\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcovered: coveredIds.length,\n\t\t\ttopics: summary.topics,\n\t\t});\n\t\treturn summary;\n\t}\n\n\t/** Look up an existing summary on this branch with a matching root. */\n\tprivate _findExistingForRoot(\n\t\tsessionId: string,\n\t\tbranchId: string,\n\t\trootThoughtId: string\n\t): Summary | undefined {\n\t\tfor (const s of this._deps.summaryStore.forBranch(sessionId, branchId)) {\n\t\t\tif (s.rootThoughtId === rootThoughtId) return s;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Collect the root and all of its descendants (chronological BFS). */\n\tprivate _collectCovered(sessionId: string, rootThoughtId: string): readonly string[] {\n\t\tconst descendants = this._graph.descendants(sessionId, rootThoughtId);\n\t\treturn [rootThoughtId, ...descendants];\n\t}\n\n\t/**\n\t * Resolve covered ids to {@link ThoughtData}, dropping any not found in\n\t * the history (defensive — graph may reference evicted thoughts).\n\t */\n\tprivate _lookupThoughts(sessionId: string, coveredIds: readonly string[]): ThoughtData[] {\n\t\tconst history = this._deps.historyManager.getHistory(sessionId);\n\t\tconst byId = new Map<string, ThoughtData>();\n\t\tfor (const t of history) {\n\t\t\tif (t.id !== undefined) byId.set(t.id, t);\n\t\t}\n\t\tconst out: ThoughtData[] = [];\n\t\tfor (const id of coveredIds) {\n\t\t\tconst t = byId.get(id);\n\t\t\tif (t) out.push(t);\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * Mean of (`calibrated_confidence` ?? `confidence` ?? 0) across covered.\n\t * Returns 0 when no thoughts are covered.\n\t */\n\tprivate _meanConfidence(thoughts: readonly ThoughtData[]): number {\n\t\tif (thoughts.length === 0) return 0;\n\t\tlet sum = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tconst withSignals = t as ThoughtWithSignals;\n\t\t\tconst calibrated = withSignals.confidence_signals?.calibrated_confidence;\n\t\t\tsum += calibrated ?? t.confidence ?? 0;\n\t\t}\n\t\treturn sum / thoughts.length;\n\t}\n\n\t/**\n\t * Inclusive `[min, max]` of `thought_number` across covered thoughts.\n\t * Returns `[0, 0]` when no thoughts are covered.\n\t */\n\tprivate _coveredRange(thoughts: readonly ThoughtData[]): readonly [number, number] {\n\t\tif (thoughts.length === 0) return [0, 0];\n\t\tlet min = Number.POSITIVE_INFINITY;\n\t\tlet max = Number.NEGATIVE_INFINITY;\n\t\tfor (const t of thoughts) {\n\t\t\tconst n = t.thought_number;\n\t\t\tif (n < min) min = n;\n\t\t\tif (n > max) max = n;\n\t\t}\n\t\treturn [min, max];\n\t}\n\n\t/**\n\t * Extract top-3 unigrams by frequency from concatenated thought text.\n\t * Ties broken by first-occurrence order (stable).\n\t */\n\tprivate _extractTopics(thoughts: readonly ThoughtData[]): readonly string[] {\n\t\tif (thoughts.length === 0) return [];\n\t\tconst counts = new Map<string, number>();\n\t\tconst order = new Map<string, number>();\n\t\tlet position = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tfor (const raw of (t.thought ?? '').split(/\\s+/)) {\n\t\t\t\tconst token = this._normalizeToken(raw);\n\t\t\t\tif (token === null) continue;\n\t\t\t\tif (!counts.has(token)) order.set(token, position++);\n\t\t\t\tcounts.set(token, (counts.get(token) ?? 0) + 1);\n\t\t\t}\n\t\t}\n\t\tif (counts.size === 0) return [];\n\t\tconst entries = Array.from(counts.entries());\n\t\tentries.sort((a, b) => {\n\t\t\tif (b[1] !== a[1]) return b[1] - a[1];\n\t\t\treturn (order.get(a[0]) ?? 0) - (order.get(b[0]) ?? 0);\n\t\t});\n\t\treturn entries.slice(0, TOP_TOPICS).map(([word]) => word);\n\t}\n\n\t/** Lowercase + strip non-alphanumerics; reject if too short or a stopword. */\n\tprivate _normalizeToken(raw: string): string | null {\n\t\tconst cleaned = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');\n\t\tif (cleaned.length < MIN_TOKEN_LENGTH) return null;\n\t\tif (STOPWORDS.has(cleaned)) return null;\n\t\treturn cleaned;\n\t}\n}\n"],"names":["STOPWORDS","Set","MIN_TOKEN_LENGTH","TOP_TOPICS","CompressionService","deps","GraphView","sessionId","branchId","rootThoughtId","existing","coveredIds","thoughts","summary","generateUlid","Date","s","descendants","history","byId","Map","t","undefined","out","id","sum","withSignals","calibrated","min","Number","max","n","counts","order","position","raw","token","entries","Array","a","b","word","cleaned"],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module core/compression/Summary
|
|
11
11
|
*/
|
|
12
|
+
import type { SessionId, ThoughtId } from '../../contracts/ids.js';
|
|
12
13
|
/**
|
|
13
14
|
* Immutable record describing a compressed group of thoughts.
|
|
14
15
|
*
|
|
@@ -34,13 +35,13 @@ export interface Summary {
|
|
|
34
35
|
/** Unique identifier (ulid). */
|
|
35
36
|
readonly id: string;
|
|
36
37
|
/** Session this summary belongs to. */
|
|
37
|
-
readonly sessionId:
|
|
38
|
+
readonly sessionId: SessionId;
|
|
38
39
|
/** Optional branch id; `undefined` indicates main-chain compression. */
|
|
39
40
|
readonly branchId?: string;
|
|
40
41
|
/** `id` of the thought that anchors the compressed subtree. */
|
|
41
|
-
readonly rootThoughtId:
|
|
42
|
+
readonly rootThoughtId: ThoughtId;
|
|
42
43
|
/** Thought ids included in this summary, in chronological order. */
|
|
43
|
-
readonly coveredIds: readonly
|
|
44
|
+
readonly coveredIds: readonly ThoughtId[];
|
|
44
45
|
/** Inclusive `[min, max]` of `thought_number` values covered. */
|
|
45
46
|
readonly coveredRange: readonly [number, number];
|
|
46
47
|
/** Top-3 unigrams extracted from the covered thought texts. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Summary.d.ts","sourceRoot":"","sources":["../../../src/core/compression/Summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"Summary.d.ts","sourceRoot":"","sources":["../../../src/core/compression/Summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,OAAO;IACvB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,aAAa,EAAE,SAAS,CAAC;IAClC,oEAAoE;IACpE,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,8DAA8D;IAC9D,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC"}
|
|
@@ -7,11 +7,18 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module core/graph/Edge
|
|
9
9
|
*/
|
|
10
|
+
import type { EdgeId, SessionId, ThoughtId } from '../../contracts/ids.js';
|
|
10
11
|
/**
|
|
11
12
|
* Kinds of relationships between thoughts in the DAG.
|
|
12
13
|
*
|
|
13
14
|
* Each kind represents a semantic relationship that the reasoning controller
|
|
14
15
|
* can use for search policy decisions.
|
|
16
|
+
*
|
|
17
|
+
* NOTE: Kept as a hand-written union (not inferred from `EdgeKindSchema`) because
|
|
18
|
+
* `schema.ts` imports `EdgeKind` from this file to constrain the schema via
|
|
19
|
+
* `satisfies v.GenericSchema<EdgeKind>`. Reversing the dependency would create a
|
|
20
|
+
* circular import (schema.ts → Edge.ts → schema.ts). The `satisfies` clause in
|
|
21
|
+
* schema.ts already guarantees the schema and the union stay in sync.
|
|
15
22
|
*/
|
|
16
23
|
export type EdgeKind = 'sequence' | 'branch' | 'merge' | 'verifies' | 'critiques' | 'derives_from' | 'tool_invocation' | 'revises';
|
|
17
24
|
/**
|
|
@@ -34,15 +41,15 @@ export type EdgeKind = 'sequence' | 'branch' | 'merge' | 'verifies' | 'critiques
|
|
|
34
41
|
*/
|
|
35
42
|
export interface Edge {
|
|
36
43
|
/** Unique edge identifier (ulid). */
|
|
37
|
-
readonly id:
|
|
44
|
+
readonly id: EdgeId;
|
|
38
45
|
/** Source thought id. */
|
|
39
|
-
readonly from:
|
|
46
|
+
readonly from: ThoughtId;
|
|
40
47
|
/** Target thought id. */
|
|
41
|
-
readonly to:
|
|
48
|
+
readonly to: ThoughtId;
|
|
42
49
|
/** Semantic relationship kind. */
|
|
43
50
|
readonly kind: EdgeKind;
|
|
44
51
|
/** Session this edge belongs to. */
|
|
45
|
-
readonly sessionId:
|
|
52
|
+
readonly sessionId: SessionId;
|
|
46
53
|
/** Creation timestamp (`Date.now()`). */
|
|
47
54
|
readonly createdAt: number;
|
|
48
55
|
/** Optional metadata for strategy-specific annotations. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Edge.d.ts","sourceRoot":"","sources":["../../../src/core/graph/Edge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH
|
|
1
|
+
{"version":3,"file":"Edge.d.ts","sourceRoot":"","sources":["../../../src/core/graph/Edge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAE3E;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,QAAQ,GACjB,UAAU,GACV,QAAQ,GACR,OAAO,GACP,UAAU,GACV,WAAW,GACX,cAAc,GACd,iBAAiB,GACjB,SAAS,CAAC;AAEb;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,IAAI;IACpB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IACvB,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getErrorMessage } from "../../errors.js";
|
|
2
2
|
import { NullLogger } from "../../logger/NullLogger.js";
|
|
3
|
-
import {
|
|
3
|
+
import { generateEdgeId } from "../../contracts/ids.js";
|
|
4
4
|
class EdgeEmitter {
|
|
5
5
|
_edgeStore;
|
|
6
6
|
_dagEdges;
|
|
@@ -72,11 +72,11 @@ class EdgeEmitter {
|
|
|
72
72
|
return false;
|
|
73
73
|
}
|
|
74
74
|
const edge = {
|
|
75
|
-
id:
|
|
76
|
-
from,
|
|
77
|
-
to,
|
|
75
|
+
id: generateEdgeId(),
|
|
76
|
+
from: from,
|
|
77
|
+
to: to,
|
|
78
78
|
kind,
|
|
79
|
-
sessionId,
|
|
79
|
+
sessionId: sessionId,
|
|
80
80
|
createdAt: Date.now(),
|
|
81
81
|
...void 0 !== metadata ? {
|
|
82
82
|
metadata
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/graph/EdgeEmitter.js","sources":["../../../src/core/graph/EdgeEmitter.ts"],"sourcesContent":["/**\n * EdgeEmitter — emits DAG edges for thoughts based on their metadata.\n *\n * Stateless helper extracted from HistoryManager. Holds a reference to an\n * optional `IEdgeStore` and a feature flag (`dagEdges`) gating writes.\n *\n * @module EdgeEmitter\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport { getErrorMessage } from '../../errors.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport { NullLogger } from '../../logger/NullLogger.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { Edge, EdgeKind } from './Edge.js';\nimport { generateUlid } from '../ids.js';\n\n/** Minimal session view needed for edge emission. */\nexport interface EdgeEmissionSession {\n\tthought_history: ThoughtData[];\n\tbranches: Record<string, ThoughtData[]>;\n}\n\n/** Configuration options for EdgeEmitter. */\nexport interface EdgeEmitterConfig {\n\tedgeStore?: IEdgeStore;\n\tdagEdges?: boolean;\n\tdefaultSessionId: string;\n\tlogger?: Logger;\n}\n\n/**\n * Emits DAG edges for thought relationships when an `IEdgeStore` is configured\n * and the `dagEdges` feature flag is enabled. No-ops otherwise.\n */\nexport class EdgeEmitter {\n\tprivate readonly _edgeStore?: IEdgeStore;\n\tprivate readonly _dagEdges: boolean;\n\tprivate readonly _defaultSessionId: string;\n\tprivate readonly _logger: Logger;\n\n\tconstructor(config: EdgeEmitterConfig) {\n\t\tthis._edgeStore = config.edgeStore;\n\t\tthis._dagEdges = config.dagEdges ?? true;\n\t\tthis._defaultSessionId = config.defaultSessionId;\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t}\n\n\t/** Returns true when edge emission is active (store + flag both set). */\n\tpublic isEnabled(): boolean {\n\t\treturn this._edgeStore !== undefined && this._dagEdges;\n\t}\n\n\t/**\n\t * Emits DAG edges for a thought based on its metadata fields.\n\t *\n\t * Edge kinds (in priority order):\n\t * - branch: branch_from_thought + branch_id → parent.id → current.id\n\t * - merge: merge_from_thoughts → source.id → current.id (per source)\n\t * - verifies: verification_target + thought_type=verification → current.id → target.id\n\t * - critiques: verification_target + thought_type=critique → current.id → target.id\n\t * - derives_from: synthesis_sources → source.id → current.id (per source)\n\t * - revises: revises_thought → current.id → target.id\n\t * - tool_invocation: tool_observation with _resumedFrom → tool_call.id → current.id\n\t * - sequence: default chronological link from previous thought (if none of the above)\n\t */\n\tpublic emitEdgesForThought(session: EdgeEmissionSession, thought: ThoughtData): void {\n\t\tif (!this._edgeStore || !this._dagEdges) return;\n\t\tif (!thought.id) return;\n\n\t\tconst sessionId = thought.session_id ?? this._defaultSessionId;\n\t\tlet emittedRelational = false;\n\n\t\tif (thought.branch_from_thought !== undefined && thought.branch_id) {\n\t\t\tconst parentId = this.resolveThoughtId(session, thought.branch_from_thought);\n\t\t\tif (this._addEdgeIfValid(parentId, thought.id, 'branch', sessionId)) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\tif (thought.merge_from_thoughts?.length) {\n\t\t\tfor (const src of thought.merge_from_thoughts) {\n\t\t\t\tconst srcId = this.resolveThoughtId(session, src);\n\t\t\t\tif (this._addEdgeIfValid(srcId, thought.id, 'merge', sessionId)) {\n\t\t\t\t\temittedRelational = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (thought.verification_target !== undefined && thought.thought_type === 'verification') {\n\t\t\tconst targetId = this.resolveThoughtId(session, thought.verification_target);\n\t\t\tif (this._addEdgeIfValid(thought.id, targetId, 'verifies', sessionId)) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\tif (thought.verification_target !== undefined && thought.thought_type === 'critique') {\n\t\t\tconst targetId = this.resolveThoughtId(session, thought.verification_target);\n\t\t\tif (this._addEdgeIfValid(thought.id, targetId, 'critiques', sessionId)) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\tif (thought.synthesis_sources?.length) {\n\t\t\tfor (const src of thought.synthesis_sources) {\n\t\t\t\tconst srcId = this.resolveThoughtId(session, src);\n\t\t\t\tif (this._addEdgeIfValid(srcId, thought.id, 'derives_from', sessionId)) {\n\t\t\t\t\temittedRelational = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (thought.revises_thought !== undefined) {\n\t\t\tconst targetId = this.resolveThoughtId(session, thought.revises_thought);\n\t\t\tif (this._addEdgeIfValid(thought.id, targetId, 'revises', sessionId)) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\t// tool_invocation edge: tool_call → tool_observation\n\t\tif (thought.thought_type === 'tool_observation' && thought._resumedFrom !== undefined) {\n\t\t\tconst toolCallId = this.resolveThoughtId(session, thought._resumedFrom);\n\t\t\tconst meta: Record<string, unknown> = {};\n\t\t\tif (thought.tool_name !== undefined) meta.tool_name = thought.tool_name;\n\t\t\tif (\n\t\t\t\tthis._addEdgeIfValid(\n\t\t\t\t\ttoolCallId,\n\t\t\t\t\tthought.id,\n\t\t\t\t\t'tool_invocation',\n\t\t\t\t\tsessionId,\n\t\t\t\t\tObject.keys(meta).length > 0 ? meta : undefined\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!emittedRelational) {\n\t\t\t// Default: chronological sequence from previous thought (the one before current).\n\t\t\t// current was just pushed, so prev is at length - 2.\n\t\t\tconst history = session.thought_history;\n\t\t\tif (history.length >= 2) {\n\t\t\t\tconst prev = history[history.length - 2]!;\n\t\t\t\tif (prev.id) {\n\t\t\t\t\tthis._addEdgeIfValid(prev.id, thought.id, 'sequence', sessionId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Resolves a thought_number to its stable id within the given session.\n\t * Searches main history first, then branches.\n\t *\n\t * @returns The thought's id if found and non-empty, undefined otherwise\n\t */\n\tpublic resolveThoughtId(\n\t\tsession: EdgeEmissionSession,\n\t\tthoughtNumber: number\n\t): string | undefined {\n\t\tfor (const t of session.thought_history) {\n\t\t\tif (t.thought_number === thoughtNumber && typeof t.id === 'string' && t.id.length > 0) {\n\t\t\t\treturn t.id;\n\t\t\t}\n\t\t}\n\t\tfor (const branchThoughts of Object.values(session.branches)) {\n\t\t\tfor (const t of branchThoughts) {\n\t\t\t\tif (t.thought_number === thoughtNumber && typeof t.id === 'string' && t.id.length > 0) {\n\t\t\t\t\treturn t.id;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Adds an edge to the edge store if both endpoints are non-empty strings.\n\t * Returns true if added, false if skipped (missing endpoint).\n\t * Failures (e.g. self-edge) are caught and logged.\n\t */\n\tprivate _addEdgeIfValid(\n\t\tfrom: string | undefined,\n\t\tto: string | undefined,\n\t\tkind: EdgeKind,\n\t\tsessionId: string,\n\t\tmetadata?: Record<string, unknown>\n\t): boolean {\n\t\tif (!from || !to) {\n\t\t\tthis._logger.debug('Skipping edge: unresolved endpoint', {\n\t\t\t\tkind,\n\t\t\t\tfrom: from ?? null,\n\t\t\t\tto: to ?? null,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tconst edge: Edge = {\n\t\t\tid: generateUlid(),\n\t\t\tfrom,\n\t\t\tto,\n\t\t\tkind,\n\t\t\tsessionId,\n\t\t\tcreatedAt: Date.now(),\n\t\t\t...(metadata !== undefined ? { metadata } : {}),\n\t\t};\n\t\ttry {\n\t\t\tthis._edgeStore!.addEdge(edge);\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tthis._logger.info('Failed to add DAG edge', {\n\t\t\t\tkind,\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"names":["EdgeEmitter","config","NullLogger","undefined","session","thought","sessionId","emittedRelational","parentId","src","srcId","targetId","toolCallId","meta","Object","history","prev","thoughtNumber","t","branchThoughts","from","to","kind","metadata","edge","generateUlid","Date","err","getErrorMessage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core/graph/EdgeEmitter.js","sources":["../../../src/core/graph/EdgeEmitter.ts"],"sourcesContent":["/**\n * EdgeEmitter — emits DAG edges for thoughts based on their metadata.\n *\n * Stateless helper extracted from HistoryManager. Holds a reference to an\n * optional `IEdgeStore` and a feature flag (`dagEdges`) gating writes.\n *\n * @module EdgeEmitter\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport { getErrorMessage } from '../../errors.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport { NullLogger } from '../../logger/NullLogger.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { Edge, EdgeKind } from './Edge.js';\nimport { generateEdgeId } from '../../contracts/ids.js';\n\n/** Minimal session view needed for edge emission. */\nexport interface EdgeEmissionSession {\n\tthought_history: ThoughtData[];\n\tbranches: Record<string, ThoughtData[]>;\n}\n\n/** Configuration options for EdgeEmitter. */\nexport interface EdgeEmitterConfig {\n\tedgeStore?: IEdgeStore;\n\tdagEdges?: boolean;\n\tdefaultSessionId: string;\n\tlogger?: Logger;\n}\n\n/**\n * Emits DAG edges for thought relationships when an `IEdgeStore` is configured\n * and the `dagEdges` feature flag is enabled. No-ops otherwise.\n */\nexport class EdgeEmitter {\n\tprivate readonly _edgeStore?: IEdgeStore;\n\tprivate readonly _dagEdges: boolean;\n\tprivate readonly _defaultSessionId: string;\n\tprivate readonly _logger: Logger;\n\n\tconstructor(config: EdgeEmitterConfig) {\n\t\tthis._edgeStore = config.edgeStore;\n\t\tthis._dagEdges = config.dagEdges ?? true;\n\t\tthis._defaultSessionId = config.defaultSessionId;\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t}\n\n\t/** Returns true when edge emission is active (store + flag both set). */\n\tpublic isEnabled(): boolean {\n\t\treturn this._edgeStore !== undefined && this._dagEdges;\n\t}\n\n\t/**\n\t * Emits DAG edges for a thought based on its metadata fields.\n\t *\n\t * Edge kinds (in priority order):\n\t * - branch: branch_from_thought + branch_id → parent.id → current.id\n\t * - merge: merge_from_thoughts → source.id → current.id (per source)\n\t * - verifies: verification_target + thought_type=verification → current.id → target.id\n\t * - critiques: verification_target + thought_type=critique → current.id → target.id\n\t * - derives_from: synthesis_sources → source.id → current.id (per source)\n\t * - revises: revises_thought → current.id → target.id\n\t * - tool_invocation: tool_observation with _resumedFrom → tool_call.id → current.id\n\t * - sequence: default chronological link from previous thought (if none of the above)\n\t */\n\tpublic emitEdgesForThought(session: EdgeEmissionSession, thought: ThoughtData): void {\n\t\tif (!this._edgeStore || !this._dagEdges) return;\n\t\tif (!thought.id) return;\n\n\t\tconst sessionId = thought.session_id ?? this._defaultSessionId;\n\t\tlet emittedRelational = false;\n\n\t\tif (thought.branch_from_thought !== undefined && thought.branch_id) {\n\t\t\tconst parentId = this.resolveThoughtId(session, thought.branch_from_thought);\n\t\t\tif (this._addEdgeIfValid(parentId, thought.id, 'branch', sessionId)) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\tif (thought.merge_from_thoughts?.length) {\n\t\t\tfor (const src of thought.merge_from_thoughts) {\n\t\t\t\tconst srcId = this.resolveThoughtId(session, src);\n\t\t\t\tif (this._addEdgeIfValid(srcId, thought.id, 'merge', sessionId)) {\n\t\t\t\t\temittedRelational = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (thought.verification_target !== undefined && thought.thought_type === 'verification') {\n\t\t\tconst targetId = this.resolveThoughtId(session, thought.verification_target);\n\t\t\tif (this._addEdgeIfValid(thought.id, targetId, 'verifies', sessionId)) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\tif (thought.verification_target !== undefined && thought.thought_type === 'critique') {\n\t\t\tconst targetId = this.resolveThoughtId(session, thought.verification_target);\n\t\t\tif (this._addEdgeIfValid(thought.id, targetId, 'critiques', sessionId)) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\tif (thought.synthesis_sources?.length) {\n\t\t\tfor (const src of thought.synthesis_sources) {\n\t\t\t\tconst srcId = this.resolveThoughtId(session, src);\n\t\t\t\tif (this._addEdgeIfValid(srcId, thought.id, 'derives_from', sessionId)) {\n\t\t\t\t\temittedRelational = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (thought.revises_thought !== undefined) {\n\t\t\tconst targetId = this.resolveThoughtId(session, thought.revises_thought);\n\t\t\tif (this._addEdgeIfValid(thought.id, targetId, 'revises', sessionId)) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\t// tool_invocation edge: tool_call → tool_observation\n\t\tif (thought.thought_type === 'tool_observation' && thought._resumedFrom !== undefined) {\n\t\t\tconst toolCallId = this.resolveThoughtId(session, thought._resumedFrom);\n\t\t\tconst meta: Record<string, unknown> = {};\n\t\t\tif (thought.tool_name !== undefined) meta.tool_name = thought.tool_name;\n\t\t\tif (\n\t\t\t\tthis._addEdgeIfValid(\n\t\t\t\t\ttoolCallId,\n\t\t\t\t\tthought.id,\n\t\t\t\t\t'tool_invocation',\n\t\t\t\t\tsessionId,\n\t\t\t\t\tObject.keys(meta).length > 0 ? meta : undefined\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\temittedRelational = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!emittedRelational) {\n\t\t\t// Default: chronological sequence from previous thought (the one before current).\n\t\t\t// current was just pushed, so prev is at length - 2.\n\t\t\tconst history = session.thought_history;\n\t\t\tif (history.length >= 2) {\n\t\t\t\tconst prev = history[history.length - 2]!;\n\t\t\t\tif (prev.id) {\n\t\t\t\t\tthis._addEdgeIfValid(prev.id, thought.id, 'sequence', sessionId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Resolves a thought_number to its stable id within the given session.\n\t * Searches main history first, then branches.\n\t *\n\t * @returns The thought's id if found and non-empty, undefined otherwise\n\t */\n\tpublic resolveThoughtId(\n\t\tsession: EdgeEmissionSession,\n\t\tthoughtNumber: number\n\t): string | undefined {\n\t\tfor (const t of session.thought_history) {\n\t\t\tif (t.thought_number === thoughtNumber && typeof t.id === 'string' && t.id.length > 0) {\n\t\t\t\treturn t.id;\n\t\t\t}\n\t\t}\n\t\tfor (const branchThoughts of Object.values(session.branches)) {\n\t\t\tfor (const t of branchThoughts) {\n\t\t\t\tif (t.thought_number === thoughtNumber && typeof t.id === 'string' && t.id.length > 0) {\n\t\t\t\t\treturn t.id;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Adds an edge to the edge store if both endpoints are non-empty strings.\n\t * Returns true if added, false if skipped (missing endpoint).\n\t * Failures (e.g. self-edge) are caught and logged.\n\t */\n\tprivate _addEdgeIfValid(\n\t\tfrom: string | undefined,\n\t\tto: string | undefined,\n\t\tkind: EdgeKind,\n\t\tsessionId: string,\n\t\tmetadata?: Record<string, unknown>\n\t): boolean {\n\t\tif (!from || !to) {\n\t\t\tthis._logger.debug('Skipping edge: unresolved endpoint', {\n\t\t\t\tkind,\n\t\t\t\tfrom: from ?? null,\n\t\t\t\tto: to ?? null,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tconst edge: Edge = {\n\t\t\tid: generateEdgeId(),\n\t\t\tfrom: from as Edge['from'],\n\t\t\tto: to as Edge['to'],\n\t\t\tkind,\n\t\t\tsessionId: sessionId as Edge['sessionId'],\n\t\t\tcreatedAt: Date.now(),\n\t\t\t...(metadata !== undefined ? { metadata } : {}),\n\t\t};\n\t\ttry {\n\t\t\tthis._edgeStore!.addEdge(edge);\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tthis._logger.info('Failed to add DAG edge', {\n\t\t\t\tkind,\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"names":["EdgeEmitter","config","NullLogger","undefined","session","thought","sessionId","emittedRelational","parentId","src","srcId","targetId","toolCallId","meta","Object","history","prev","thoughtNumber","t","branchThoughts","from","to","kind","metadata","edge","generateEdgeId","Date","err","getErrorMessage"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module core/reasoning/strategies/StrategyFactory
|
|
9
9
|
*/
|
|
10
10
|
import type { IReasoningStrategy } from '../../../contracts/strategy.js';
|
|
11
|
-
import type { FeatureFlags } from '../../../
|
|
11
|
+
import type { FeatureFlags } from '../../../contracts/features.js';
|
|
12
12
|
/**
|
|
13
13
|
* Build a reasoning strategy by name.
|
|
14
14
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StrategyFactory.d.ts","sourceRoot":"","sources":["../../../../src/core/reasoning/strategies/StrategyFactory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"StrategyFactory.d.ts","sourceRoot":"","sources":["../../../../src/core/reasoning/strategies/StrategyFactory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAInE;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,YAAY,CAAC,mBAAmB,CAAC,GACrC,kBAAkB,CAYpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/reasoning/strategies/StrategyFactory.js","sources":["../../../../src/core/reasoning/strategies/StrategyFactory.ts"],"sourcesContent":["/**\n * Strategy factory — maps a {@link FeatureFlags.reasoningStrategy} value to\n * a concrete {@link IReasoningStrategy} instance.\n *\n * Today {@link SequentialStrategy} and {@link TreeOfThoughtStrategy} are\n * implemented and are the only valid strategy values.\n *\n * @module core/reasoning/strategies/StrategyFactory\n */\n\nimport type { IReasoningStrategy } from '../../../contracts/strategy.js';\nimport type { FeatureFlags } from '../../../
|
|
1
|
+
{"version":3,"file":"core/reasoning/strategies/StrategyFactory.js","sources":["../../../../src/core/reasoning/strategies/StrategyFactory.ts"],"sourcesContent":["/**\n * Strategy factory — maps a {@link FeatureFlags.reasoningStrategy} value to\n * a concrete {@link IReasoningStrategy} instance.\n *\n * Today {@link SequentialStrategy} and {@link TreeOfThoughtStrategy} are\n * implemented and are the only valid strategy values.\n *\n * @module core/reasoning/strategies/StrategyFactory\n */\n\nimport type { IReasoningStrategy } from '../../../contracts/strategy.js';\nimport type { FeatureFlags } from '../../../contracts/features.js';\nimport { SequentialStrategy } from './SequentialStrategy.js';\nimport { TreeOfThoughtStrategy } from './TreeOfThoughtStrategy.js';\n\n/**\n * Build a reasoning strategy by name.\n *\n * @param name - Strategy identifier from {@link FeatureFlags.reasoningStrategy}.\n * @returns A concrete {@link IReasoningStrategy} instance.\n *\n * @example\n * ```ts\n * const strategy = createReasoningStrategy(config.features.reasoningStrategy);\n * const decision = strategy.decide(ctx);\n * ```\n */\nexport function createReasoningStrategy(\n\tname: FeatureFlags['reasoningStrategy'],\n): IReasoningStrategy {\n\tswitch (name) {\n\t\tcase 'sequential':\n\t\t\treturn new SequentialStrategy();\n\t\tcase 'tot':\n\t\t\treturn new TreeOfThoughtStrategy();\n\t\tdefault: {\n\t\t\tconst _exhaust: never = name;\n\t\t\tvoid _exhaust;\n\t\t\treturn new SequentialStrategy();\n\t\t}\n\t}\n}\n"],"names":["createReasoningStrategy","name","SequentialStrategy","TreeOfThoughtStrategy"],"mappings":";;AA2BO,SAASA,wBACfC,IAAuC;IAEvC,OAAQA;QACP,KAAK;YACJ,OAAO,IAAIC;QACZ,KAAK;YACJ,OAAO,IAAIC;QACZ;YAGC,OAAO,IAAID;IAEb;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeOfThoughtStrategy.d.ts","sourceRoot":"","sources":["../../../../src/core/reasoning/strategies/TreeOfThoughtStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,MAAM,gCAAgC,CAAC;AAKxC;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CACjC;AAgED;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,YAAW,kBAAkB;IAC/D,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAE/B,6CAA6C;gBACjC,MAAM,CAAC,EAAE,SAAS;IAI9B;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,gBAAgB;
|
|
1
|
+
{"version":3,"file":"TreeOfThoughtStrategy.d.ts","sourceRoot":"","sources":["../../../../src/core/reasoning/strategies/TreeOfThoughtStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,MAAM,gCAAgC,CAAC;AAKxC;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CACjC;AAgED;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,YAAW,kBAAkB;IAC/D,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAE/B,6CAA6C;gBACjC,MAAM,CAAC,EAAE,SAAS;IAI9B;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,gBAAgB;IAiC9C,2EAA2E;IAC3E,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;IAO3C,iFAAiF;IACjF,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;CAY9C"}
|
|
@@ -51,6 +51,9 @@ class TreeOfThoughtStrategy {
|
|
|
51
51
|
}
|
|
52
52
|
decide(ctx) {
|
|
53
53
|
const cfg = configOf(this);
|
|
54
|
+
if (!ctx.graph) return {
|
|
55
|
+
action: 'continue'
|
|
56
|
+
};
|
|
54
57
|
const frontier = ctx.graph.leaves(ctx.sessionId);
|
|
55
58
|
const byKey = indexHistory(ctx.history);
|
|
56
59
|
const scored = scoreFrontier(frontier, byKey);
|
|
@@ -80,11 +83,13 @@ class TreeOfThoughtStrategy {
|
|
|
80
83
|
}
|
|
81
84
|
shouldBranch(ctx) {
|
|
82
85
|
const cfg = configOf(this);
|
|
86
|
+
if (!ctx.graph) return false;
|
|
83
87
|
const frontier = ctx.graph.leaves(ctx.sessionId);
|
|
84
88
|
return frontier.length > cfg.beamWidth;
|
|
85
89
|
}
|
|
86
90
|
shouldTerminate(ctx) {
|
|
87
91
|
const cfg = configOf(this);
|
|
92
|
+
if (!ctx.graph) return false;
|
|
88
93
|
const frontier = ctx.graph.leaves(ctx.sessionId);
|
|
89
94
|
const byKey = indexHistory(ctx.history);
|
|
90
95
|
const scored = scoreFrontier(frontier, byKey);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/reasoning/strategies/TreeOfThoughtStrategy.js","sources":["../../../../src/core/reasoning/strategies/TreeOfThoughtStrategy.ts"],"sourcesContent":["/**\n * Tree-of-Thought reasoning strategy — beam search over the thought DAG.\n *\n * Observes the frontier (graph leaves), scores each leaf via\n * {@link scoreThought}, and decides whether to continue, branch (when the\n * current thought falls outside the beam), or terminate (on confidence\n * threshold or score plateau).\n *\n * Pure policy: configuration lives in a module-level {@link WeakMap}, not\n * on the instance, so `Object.getOwnPropertyNames(strategy)` only ever\n * surfaces the readonly `name` discriminator. All other state is derived\n * from the {@link StrategyContext} on every call.\n *\n * @module core/reasoning/strategies/TreeOfThoughtStrategy\n */\n\nimport type {\n\tIReasoningStrategy,\n\tStrategyContext,\n\tStrategyDecision,\n} from '../../../contracts/strategy.js';\nimport type { ThoughtData } from '../../thought.js';\nimport { scoreThought, selectBeam, type ScoredCandidate } from './totScoring.js';\nimport { detectPlateau } from './plateau.js';\n\n/**\n * Configuration knobs for {@link TreeOfThoughtStrategy}. All fields are\n * optional; defaults are applied in the constructor.\n */\nexport interface TotConfig {\n\t/** Top-K candidates kept on the frontier (default `3`). */\n\treadonly beamWidth?: number;\n\t/** Maximum exploration depth before forcing termination (default `8`). */\n\treadonly depthCap?: number;\n\t/** Score at/above which the chain terminates (default `0.85`). */\n\treadonly terminationConfidence?: number;\n\t/** Window size for plateau detection (default `3`). */\n\treadonly plateauWindow?: number;\n\t/** Minimum meaningful score change for plateau detection (default `0.02`). */\n\treadonly plateauEpsilon?: number;\n}\n\n/** Defaults applied when a {@link TotConfig} field is omitted. */\nconst DEFAULTS: Required<TotConfig> = {\n\tbeamWidth: 3,\n\tdepthCap: 8,\n\tterminationConfidence: 0.85,\n\tplateauWindow: 3,\n\tplateauEpsilon: 0.02,\n};\n\n/**\n * Module-private config storage. Keyed by strategy instance so that no\n * own-properties leak onto `this` (preserving the purity contract).\n */\nconst CONFIGS: WeakMap<TreeOfThoughtStrategy, Required<TotConfig>> = new WeakMap();\n\n/** Resolve the per-instance config (constructor always populates the map). */\nfunction configOf(s: TreeOfThoughtStrategy): Required<TotConfig> {\n\treturn CONFIGS.get(s) ?? DEFAULTS;\n}\n\n/** Stable identifier for a thought: `id` if present, else its sequence number. */\nfunction thoughtKey(t: ThoughtData): string {\n\treturn t.id ?? String(t.thought_number);\n}\n\n/** Index history by stable key for O(1) leaf-id → ThoughtData lookup. */\nfunction indexHistory(history: readonly ThoughtData[]): Map<string, ThoughtData> {\n\tconst out = new Map<string, ThoughtData>();\n\tfor (const t of history) out.set(thoughtKey(t), t);\n\treturn out;\n}\n\n/** Score the frontier (graph leaves), skipping ids absent from history. */\nfunction scoreFrontier(\n\tfrontier: readonly string[],\n\tbyKey: Map<string, ThoughtData>\n): ScoredCandidate[] {\n\tconst out: ScoredCandidate[] = [];\n\tfor (const id of frontier) {\n\t\tconst t = byKey.get(id);\n\t\tif (t !== undefined) out.push({ id, score: scoreThought(t) });\n\t}\n\treturn out;\n}\n\n/** Highest score in a candidate set, or `-Infinity` when empty. */\nfunction bestScore(scored: readonly ScoredCandidate[]): number {\n\tlet best = Number.NEGATIVE_INFINITY;\n\tfor (const c of scored) {\n\t\tif (c.score > best) best = c.score;\n\t}\n\treturn best;\n}\n\n/** Recent per-thought scores, used for plateau detection. */\nfunction recentScores(history: readonly ThoughtData[], window: number): number[] {\n\tconst start = history.length > window ? history.length - window : 0;\n\tconst out: number[] = [];\n\tfor (let i = start; i < history.length; i++) out.push(scoreThought(history[i]!));\n\treturn out;\n}\n\n/**\n * Tree-of-Thought strategy: beam search over the thought DAG. Pure policy.\n *\n * @example\n * ```typescript\n * const strategy = new TreeOfThoughtStrategy({ beamWidth: 4 });\n * const decision = strategy.decide(ctx);\n * ```\n */\nexport class TreeOfThoughtStrategy implements IReasoningStrategy {\n\treadonly name = 'tot' as const;\n\n\t/** @param config - See {@link TotConfig}. */\n\tconstructor(config?: TotConfig) {\n\t\tCONFIGS.set(this, { ...DEFAULTS, ...(config ?? {}) });\n\t}\n\n\t/**\n\t * Compute the next action for the chain.\n\t *\n\t * Order of checks: termination by confidence → termination by plateau →\n\t * branch when the current thought is outside the beam → continue.\n\t */\n\tdecide(ctx: StrategyContext): StrategyDecision {\n\t\tconst cfg = configOf(this);\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\tconst byKey = indexHistory(ctx.history);\n\t\tconst scored = scoreFrontier(frontier, byKey);\n\
|
|
1
|
+
{"version":3,"file":"core/reasoning/strategies/TreeOfThoughtStrategy.js","sources":["../../../../src/core/reasoning/strategies/TreeOfThoughtStrategy.ts"],"sourcesContent":["/**\n * Tree-of-Thought reasoning strategy — beam search over the thought DAG.\n *\n * Observes the frontier (graph leaves), scores each leaf via\n * {@link scoreThought}, and decides whether to continue, branch (when the\n * current thought falls outside the beam), or terminate (on confidence\n * threshold or score plateau).\n *\n * Pure policy: configuration lives in a module-level {@link WeakMap}, not\n * on the instance, so `Object.getOwnPropertyNames(strategy)` only ever\n * surfaces the readonly `name` discriminator. All other state is derived\n * from the {@link StrategyContext} on every call.\n *\n * @module core/reasoning/strategies/TreeOfThoughtStrategy\n */\n\nimport type {\n\tIReasoningStrategy,\n\tStrategyContext,\n\tStrategyDecision,\n} from '../../../contracts/strategy.js';\nimport type { ThoughtData } from '../../thought.js';\nimport { scoreThought, selectBeam, type ScoredCandidate } from './totScoring.js';\nimport { detectPlateau } from './plateau.js';\n\n/**\n * Configuration knobs for {@link TreeOfThoughtStrategy}. All fields are\n * optional; defaults are applied in the constructor.\n */\nexport interface TotConfig {\n\t/** Top-K candidates kept on the frontier (default `3`). */\n\treadonly beamWidth?: number;\n\t/** Maximum exploration depth before forcing termination (default `8`). */\n\treadonly depthCap?: number;\n\t/** Score at/above which the chain terminates (default `0.85`). */\n\treadonly terminationConfidence?: number;\n\t/** Window size for plateau detection (default `3`). */\n\treadonly plateauWindow?: number;\n\t/** Minimum meaningful score change for plateau detection (default `0.02`). */\n\treadonly plateauEpsilon?: number;\n}\n\n/** Defaults applied when a {@link TotConfig} field is omitted. */\nconst DEFAULTS: Required<TotConfig> = {\n\tbeamWidth: 3,\n\tdepthCap: 8,\n\tterminationConfidence: 0.85,\n\tplateauWindow: 3,\n\tplateauEpsilon: 0.02,\n};\n\n/**\n * Module-private config storage. Keyed by strategy instance so that no\n * own-properties leak onto `this` (preserving the purity contract).\n */\nconst CONFIGS: WeakMap<TreeOfThoughtStrategy, Required<TotConfig>> = new WeakMap();\n\n/** Resolve the per-instance config (constructor always populates the map). */\nfunction configOf(s: TreeOfThoughtStrategy): Required<TotConfig> {\n\treturn CONFIGS.get(s) ?? DEFAULTS;\n}\n\n/** Stable identifier for a thought: `id` if present, else its sequence number. */\nfunction thoughtKey(t: ThoughtData): string {\n\treturn t.id ?? String(t.thought_number);\n}\n\n/** Index history by stable key for O(1) leaf-id → ThoughtData lookup. */\nfunction indexHistory(history: readonly ThoughtData[]): Map<string, ThoughtData> {\n\tconst out = new Map<string, ThoughtData>();\n\tfor (const t of history) out.set(thoughtKey(t), t);\n\treturn out;\n}\n\n/** Score the frontier (graph leaves), skipping ids absent from history. */\nfunction scoreFrontier(\n\tfrontier: readonly string[],\n\tbyKey: Map<string, ThoughtData>\n): ScoredCandidate[] {\n\tconst out: ScoredCandidate[] = [];\n\tfor (const id of frontier) {\n\t\tconst t = byKey.get(id);\n\t\tif (t !== undefined) out.push({ id, score: scoreThought(t) });\n\t}\n\treturn out;\n}\n\n/** Highest score in a candidate set, or `-Infinity` when empty. */\nfunction bestScore(scored: readonly ScoredCandidate[]): number {\n\tlet best = Number.NEGATIVE_INFINITY;\n\tfor (const c of scored) {\n\t\tif (c.score > best) best = c.score;\n\t}\n\treturn best;\n}\n\n/** Recent per-thought scores, used for plateau detection. */\nfunction recentScores(history: readonly ThoughtData[], window: number): number[] {\n\tconst start = history.length > window ? history.length - window : 0;\n\tconst out: number[] = [];\n\tfor (let i = start; i < history.length; i++) out.push(scoreThought(history[i]!));\n\treturn out;\n}\n\n/**\n * Tree-of-Thought strategy: beam search over the thought DAG. Pure policy.\n *\n * @example\n * ```typescript\n * const strategy = new TreeOfThoughtStrategy({ beamWidth: 4 });\n * const decision = strategy.decide(ctx);\n * ```\n */\nexport class TreeOfThoughtStrategy implements IReasoningStrategy {\n\treadonly name = 'tot' as const;\n\n\t/** @param config - See {@link TotConfig}. */\n\tconstructor(config?: TotConfig) {\n\t\tCONFIGS.set(this, { ...DEFAULTS, ...(config ?? {}) });\n\t}\n\n\t/**\n\t * Compute the next action for the chain.\n\t *\n\t * Order of checks: termination by confidence → termination by plateau →\n\t * branch when the current thought is outside the beam → continue.\n\t */\n\tdecide(ctx: StrategyContext): StrategyDecision {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) {\n\t\t\treturn { action: 'continue' };\n\t\t}\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\tconst byKey = indexHistory(ctx.history);\n\t\tconst scored = scoreFrontier(frontier, byKey);\n\t\tif (scored.length > 0 && bestScore(scored) >= cfg.terminationConfidence) {\n\t\t\treturn { action: 'terminate', reason: 'confidence threshold' };\n\t\t}\n\n\t\tconst recent = recentScores(ctx.history, cfg.plateauWindow);\n\t\tif (detectPlateau(recent, cfg.plateauWindow, cfg.plateauEpsilon)) {\n\t\t\treturn { action: 'terminate', reason: 'plateau' };\n\t\t}\n\n\t\tif (scored.length > cfg.beamWidth) {\n\t\t\tconst beam = selectBeam(scored, cfg.beamWidth);\n\t\t\tconst currentKey = thoughtKey(ctx.currentThought);\n\t\t\tif (!beam.includes(currentKey)) {\n\t\t\t\treturn {\n\t\t\t\t\taction: 'branch',\n\t\t\t\t\tbranchId: `tot-${ctx.currentThought.thought_number}`,\n\t\t\t\t\tfromThought: ctx.currentThought.thought_number,\n\t\t\t\t\treason: 'outside beam',\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn { action: 'continue', nextHint: 'explore frontier' };\n\t}\n\n\t/** True when the frontier is wider than the beam (diverse exploration). */\n\tshouldBranch(ctx: StrategyContext): boolean {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) return false;\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\treturn frontier.length > cfg.beamWidth;\n\t}\n\n\t/** True when the best frontier score crosses the threshold OR scores plateau. */\n\tshouldTerminate(ctx: StrategyContext): boolean {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) return false;\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\tconst byKey = indexHistory(ctx.history);\n\t\tconst scored = scoreFrontier(frontier, byKey);\n\t\tif (scored.length > 0 && bestScore(scored) >= cfg.terminationConfidence) {\n\t\t\treturn true;\n\t\t}\n\t\tconst recent = recentScores(ctx.history, cfg.plateauWindow);\n\t\treturn detectPlateau(recent, cfg.plateauWindow, cfg.plateauEpsilon);\n\t}\n}\n"],"names":["DEFAULTS","CONFIGS","WeakMap","configOf","s","thoughtKey","t","String","indexHistory","history","out","Map","scoreFrontier","frontier","byKey","id","undefined","scoreThought","bestScore","scored","best","Number","c","recentScores","window","start","i","TreeOfThoughtStrategy","config","ctx","cfg","recent","detectPlateau","beam","selectBeam","currentKey"],"mappings":"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"}
|