tracelattice 1.2.5
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/LICENSE +24 -0
- package/README.md +112 -0
- package/dist/ServerConfig.d.ts +229 -0
- package/dist/ServerConfig.d.ts.map +1 -0
- package/dist/ServerConfig.js +121 -0
- package/dist/ServerConfig.js.map +1 -0
- package/dist/__tests__/base-registry.test.d.ts +2 -0
- package/dist/__tests__/base-registry.test.d.ts.map +1 -0
- package/dist/__tests__/base-transport-cov.test.d.ts +2 -0
- package/dist/__tests__/base-transport-cov.test.d.ts.map +1 -0
- package/dist/__tests__/base-transport.test.d.ts +2 -0
- package/dist/__tests__/base-transport.test.d.ts.map +1 -0
- package/dist/__tests__/config-loader.test.d.ts +2 -0
- package/dist/__tests__/config-loader.test.d.ts.map +1 -0
- package/dist/__tests__/connection-pool-cov.test.d.ts +2 -0
- package/dist/__tests__/connection-pool-cov.test.d.ts.map +1 -0
- package/dist/__tests__/connection-pool.test.d.ts +2 -0
- package/dist/__tests__/connection-pool.test.d.ts.map +1 -0
- package/dist/__tests__/container.test.d.ts +2 -0
- package/dist/__tests__/container.test.d.ts.map +1 -0
- package/dist/__tests__/crud.test.d.ts +2 -0
- package/dist/__tests__/crud.test.d.ts.map +1 -0
- package/dist/__tests__/discovery-cache.test.d.ts +2 -0
- package/dist/__tests__/discovery-cache.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test.d.ts +2 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/factories.test.d.ts +2 -0
- package/dist/__tests__/factories.test.d.ts.map +1 -0
- package/dist/__tests__/health-checker-cov.test.d.ts +2 -0
- package/dist/__tests__/health-checker-cov.test.d.ts.map +1 -0
- package/dist/__tests__/health-checker.test.d.ts +2 -0
- package/dist/__tests__/health-checker.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/factories.d.ts +36 -0
- package/dist/__tests__/helpers/factories.d.ts.map +1 -0
- package/dist/__tests__/helpers/index.d.ts +3 -0
- package/dist/__tests__/helpers/index.d.ts.map +1 -0
- package/dist/__tests__/helpers/timers.d.ts +4 -0
- package/dist/__tests__/helpers/timers.d.ts.map +1 -0
- package/dist/__tests__/history-manager.test.d.ts +2 -0
- package/dist/__tests__/history-manager.test.d.ts.map +1 -0
- package/dist/__tests__/http-helpers-cov.test.d.ts +2 -0
- package/dist/__tests__/http-helpers-cov.test.d.ts.map +1 -0
- package/dist/__tests__/http-transport-cov.test.d.ts +2 -0
- package/dist/__tests__/http-transport-cov.test.d.ts.map +1 -0
- package/dist/__tests__/http-transport.test.d.ts +2 -0
- package/dist/__tests__/http-transport.test.d.ts.map +1 -0
- package/dist/__tests__/input-normalizer.test.d.ts +8 -0
- package/dist/__tests__/input-normalizer.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.d.ts +2 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/lib-server.test.d.ts +2 -0
- package/dist/__tests__/lib-server.test.d.ts.map +1 -0
- package/dist/__tests__/memory-persistence.test.d.ts +2 -0
- package/dist/__tests__/memory-persistence.test.d.ts.map +1 -0
- package/dist/__tests__/metrics-integration.test.d.ts +2 -0
- package/dist/__tests__/metrics-integration.test.d.ts.map +1 -0
- package/dist/__tests__/persistence.test.d.ts +2 -0
- package/dist/__tests__/persistence.test.d.ts.map +1 -0
- package/dist/__tests__/reasoning-integration.test.d.ts +11 -0
- package/dist/__tests__/reasoning-integration.test.d.ts.map +1 -0
- package/dist/__tests__/reasoning-types.test.d.ts +2 -0
- package/dist/__tests__/reasoning-types.test.d.ts.map +1 -0
- package/dist/__tests__/request-context.test.d.ts +2 -0
- package/dist/__tests__/request-context.test.d.ts.map +1 -0
- package/dist/__tests__/sanitize.test.d.ts +2 -0
- package/dist/__tests__/sanitize.test.d.ts.map +1 -0
- package/dist/__tests__/schema.test.d.ts +2 -0
- package/dist/__tests__/schema.test.d.ts.map +1 -0
- package/dist/__tests__/sequentialthinking-tools.test.d.ts +2 -0
- package/dist/__tests__/sequentialthinking-tools.test.d.ts.map +1 -0
- package/dist/__tests__/server-config.test.d.ts +2 -0
- package/dist/__tests__/server-config.test.d.ts.map +1 -0
- package/dist/__tests__/skill-discovery.test.d.ts +2 -0
- package/dist/__tests__/skill-discovery.test.d.ts.map +1 -0
- package/dist/__tests__/skill-registry.test.d.ts +2 -0
- package/dist/__tests__/skill-registry.test.d.ts.map +1 -0
- package/dist/__tests__/skill-watcher.test.d.ts +2 -0
- package/dist/__tests__/skill-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/sqlite-persistence.test.d.ts +2 -0
- package/dist/__tests__/sqlite-persistence.test.d.ts.map +1 -0
- package/dist/__tests__/sse-transport-cov.test.d.ts +2 -0
- package/dist/__tests__/sse-transport-cov.test.d.ts.map +1 -0
- package/dist/__tests__/sse-transport.test.d.ts +2 -0
- package/dist/__tests__/sse-transport.test.d.ts.map +1 -0
- package/dist/__tests__/streamable-http-cov.test.d.ts +2 -0
- package/dist/__tests__/streamable-http-cov.test.d.ts.map +1 -0
- package/dist/__tests__/streamable-http-transport.test.d.ts +2 -0
- package/dist/__tests__/streamable-http-transport.test.d.ts.map +1 -0
- package/dist/__tests__/structured-logger.test.d.ts +2 -0
- package/dist/__tests__/structured-logger.test.d.ts.map +1 -0
- package/dist/__tests__/thought-evaluator.test.d.ts +2 -0
- package/dist/__tests__/thought-evaluator.test.d.ts.map +1 -0
- package/dist/__tests__/thought-formatter.test.d.ts +2 -0
- package/dist/__tests__/thought-formatter.test.d.ts.map +1 -0
- package/dist/__tests__/thought-processor.test.d.ts +8 -0
- package/dist/__tests__/thought-processor.test.d.ts.map +1 -0
- package/dist/__tests__/tool-registry-cov.test.d.ts +2 -0
- package/dist/__tests__/tool-registry-cov.test.d.ts.map +1 -0
- package/dist/__tests__/tool-registry.test.d.ts +2 -0
- package/dist/__tests__/tool-registry.test.d.ts.map +1 -0
- package/dist/__tests__/tool-watcher.test.d.ts +2 -0
- package/dist/__tests__/tool-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/worker-manager-cov.test.d.ts +2 -0
- package/dist/__tests__/worker-manager-cov.test.d.ts.map +1 -0
- package/dist/__tests__/worker-manager.test.d.ts +2 -0
- package/dist/__tests__/worker-manager.test.d.ts.map +1 -0
- package/dist/cache/DiscoveryCache.d.ts +269 -0
- package/dist/cache/DiscoveryCache.d.ts.map +1 -0
- package/dist/cache/DiscoveryCache.js +100 -0
- package/dist/cache/DiscoveryCache.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +114 -0
- package/dist/cli.js.map +1 -0
- package/dist/cluster/WorkerManager.d.ts +166 -0
- package/dist/cluster/WorkerManager.d.ts.map +1 -0
- package/dist/cluster/WorkerManager.js +202 -0
- package/dist/cluster/WorkerManager.js.map +1 -0
- package/dist/cluster/worker.d.ts +11 -0
- package/dist/cluster/worker.d.ts.map +1 -0
- package/dist/cluster/worker.js +36 -0
- package/dist/cluster/worker.js.map +1 -0
- package/dist/config/ConfigLoader.d.ts +224 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +85 -0
- package/dist/config/ConfigLoader.js.map +1 -0
- package/dist/context/RequestContext.d.ts +61 -0
- package/dist/context/RequestContext.d.ts.map +1 -0
- package/dist/context/RequestContext.js +17 -0
- package/dist/context/RequestContext.js.map +1 -0
- package/dist/contracts/index.d.ts +10 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/interfaces.d.ts +107 -0
- package/dist/contracts/interfaces.d.ts.map +1 -0
- package/dist/contracts/interfaces.js +1 -0
- package/dist/core/HistoryManager.d.ts +514 -0
- package/dist/core/HistoryManager.d.ts.map +1 -0
- package/dist/core/HistoryManager.js +331 -0
- package/dist/core/HistoryManager.js.map +1 -0
- package/dist/core/IHistoryManager.d.ts +100 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -0
- package/dist/core/IHistoryManager.js +1 -0
- package/dist/core/InputNormalizer.d.ts +139 -0
- package/dist/core/InputNormalizer.d.ts.map +1 -0
- package/dist/core/InputNormalizer.js +101 -0
- package/dist/core/InputNormalizer.js.map +1 -0
- package/dist/core/ThoughtEvaluator.d.ts +127 -0
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -0
- package/dist/core/ThoughtEvaluator.js +346 -0
- package/dist/core/ThoughtEvaluator.js.map +1 -0
- package/dist/core/ThoughtFormatter.d.ts +133 -0
- package/dist/core/ThoughtFormatter.d.ts.map +1 -0
- package/dist/core/ThoughtFormatter.js +70 -0
- package/dist/core/ThoughtFormatter.js.map +1 -0
- package/dist/core/ThoughtProcessor.d.ts +218 -0
- package/dist/core/ThoughtProcessor.d.ts.map +1 -0
- package/dist/core/ThoughtProcessor.js +205 -0
- package/dist/core/ThoughtProcessor.js.map +1 -0
- package/dist/core/reasoning.d.ts +169 -0
- package/dist/core/reasoning.d.ts.map +1 -0
- package/dist/core/reasoning.js +1 -0
- package/dist/core/step.d.ts +45 -0
- package/dist/core/step.d.ts.map +1 -0
- package/dist/core/step.js +1 -0
- package/dist/core/thought.d.ts +190 -0
- package/dist/core/thought.d.ts.map +1 -0
- package/dist/core/thought.js +1 -0
- package/dist/di/Container.d.ts +226 -0
- package/dist/di/Container.d.ts.map +1 -0
- package/dist/di/Container.js +96 -0
- package/dist/di/Container.js.map +1 -0
- package/dist/di/ServiceRegistry.d.ts +32 -0
- package/dist/di/ServiceRegistry.d.ts.map +1 -0
- package/dist/di/ServiceRegistry.js +1 -0
- package/dist/errors.d.ts +482 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +108 -0
- package/dist/errors.js.map +1 -0
- package/dist/health/HealthChecker.d.ts +73 -0
- package/dist/health/HealthChecker.d.ts.map +1 -0
- package/dist/health/HealthChecker.js +69 -0
- package/dist/health/HealthChecker.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/lib.d.ts +205 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +219 -0
- package/dist/lib.js.map +1 -0
- package/dist/logger/NullLogger.d.ts +154 -0
- package/dist/logger/NullLogger.d.ts.map +1 -0
- package/dist/logger/NullLogger.js +24 -0
- package/dist/logger/NullLogger.js.map +1 -0
- package/dist/logger/StructuredLogger.d.ts +327 -0
- package/dist/logger/StructuredLogger.d.ts.map +1 -0
- package/dist/logger/StructuredLogger.js +72 -0
- package/dist/logger/StructuredLogger.js.map +1 -0
- package/dist/metrics/__tests__/metrics.test.d.ts +2 -0
- package/dist/metrics/__tests__/metrics.test.d.ts.map +1 -0
- package/dist/metrics/metrics.impl.d.ts +252 -0
- package/dist/metrics/metrics.impl.d.ts.map +1 -0
- package/dist/metrics/metrics.impl.js +197 -0
- package/dist/metrics/metrics.impl.js.map +1 -0
- package/dist/persistence/FilePersistence.d.ts +66 -0
- package/dist/persistence/FilePersistence.d.ts.map +1 -0
- package/dist/persistence/FilePersistence.js +132 -0
- package/dist/persistence/FilePersistence.js.map +1 -0
- package/dist/persistence/MemoryPersistence.d.ts +68 -0
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -0
- package/dist/persistence/MemoryPersistence.js +51 -0
- package/dist/persistence/MemoryPersistence.js.map +1 -0
- package/dist/persistence/PersistenceBackend.d.ts +69 -0
- package/dist/persistence/PersistenceBackend.d.ts.map +1 -0
- package/dist/persistence/PersistenceBackend.js +1 -0
- package/dist/persistence/PersistenceFactory.d.ts +21 -0
- package/dist/persistence/PersistenceFactory.d.ts.map +1 -0
- package/dist/persistence/PersistenceFactory.js +25 -0
- package/dist/persistence/PersistenceFactory.js.map +1 -0
- package/dist/persistence/SqlitePersistence.d.ts +60 -0
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -0
- package/dist/persistence/SqlitePersistence.js +136 -0
- package/dist/persistence/SqlitePersistence.js.map +1 -0
- package/dist/pool/ConnectionPool.d.ts +215 -0
- package/dist/pool/ConnectionPool.d.ts.map +1 -0
- package/dist/pool/ConnectionPool.js +187 -0
- package/dist/pool/ConnectionPool.js.map +1 -0
- package/dist/registry/BaseRegistry.d.ts +203 -0
- package/dist/registry/BaseRegistry.d.ts.map +1 -0
- package/dist/registry/BaseRegistry.js +165 -0
- package/dist/registry/BaseRegistry.js.map +1 -0
- package/dist/registry/SkillRegistry.d.ts +69 -0
- package/dist/registry/SkillRegistry.d.ts.map +1 -0
- package/dist/registry/SkillRegistry.js +88 -0
- package/dist/registry/SkillRegistry.js.map +1 -0
- package/dist/registry/ToolRegistry.d.ts +69 -0
- package/dist/registry/ToolRegistry.d.ts.map +1 -0
- package/dist/registry/ToolRegistry.js +93 -0
- package/dist/registry/ToolRegistry.js.map +1 -0
- package/dist/sanitize.d.ts +63 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +14 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/schema.d.ts +531 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +204 -0
- package/dist/schema.js.map +1 -0
- package/dist/telemetry/Telemetry.d.ts +36 -0
- package/dist/telemetry/Telemetry.d.ts.map +1 -0
- package/dist/telemetry/Telemetry.js +68 -0
- package/dist/telemetry/Telemetry.js.map +1 -0
- package/dist/telemetry/__tests__/Telemetry.test.d.ts +2 -0
- package/dist/telemetry/__tests__/Telemetry.test.d.ts.map +1 -0
- package/dist/transport/BaseTransport.d.ts +184 -0
- package/dist/transport/BaseTransport.d.ts.map +1 -0
- package/dist/transport/BaseTransport.js +200 -0
- package/dist/transport/BaseTransport.js.map +1 -0
- package/dist/transport/HttpHelpers.d.ts +60 -0
- package/dist/transport/HttpHelpers.d.ts.map +1 -0
- package/dist/transport/HttpHelpers.js +50 -0
- package/dist/transport/HttpHelpers.js.map +1 -0
- package/dist/transport/HttpTransport.d.ts +134 -0
- package/dist/transport/HttpTransport.d.ts.map +1 -0
- package/dist/transport/HttpTransport.js +175 -0
- package/dist/transport/HttpTransport.js.map +1 -0
- package/dist/transport/SseTransport.d.ts +133 -0
- package/dist/transport/SseTransport.d.ts.map +1 -0
- package/dist/transport/SseTransport.js +318 -0
- package/dist/transport/SseTransport.js.map +1 -0
- package/dist/transport/StreamableHttpTransport.d.ts +224 -0
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -0
- package/dist/transport/StreamableHttpTransport.js +407 -0
- package/dist/transport/StreamableHttpTransport.js.map +1 -0
- package/dist/types/disposable.d.ts +22 -0
- package/dist/types/disposable.d.ts.map +1 -0
- package/dist/types/disposable.js +1 -0
- package/dist/types/server-config.d.ts +32 -0
- package/dist/types/server-config.d.ts.map +1 -0
- package/dist/types/server-config.js +1 -0
- package/dist/types/skill.d.ts +69 -0
- package/dist/types/skill.d.ts.map +1 -0
- package/dist/types/skill.js +1 -0
- package/dist/types/tool.d.ts +68 -0
- package/dist/types/tool.d.ts.map +1 -0
- package/dist/types/tool.js +1 -0
- package/dist/watchers/SkillWatcher.d.ts +132 -0
- package/dist/watchers/SkillWatcher.d.ts.map +1 -0
- package/dist/watchers/SkillWatcher.js +73 -0
- package/dist/watchers/SkillWatcher.js.map +1 -0
- package/dist/watchers/ToolWatcher.d.ts +109 -0
- package/dist/watchers/ToolWatcher.d.ts.map +1 -0
- package/dist/watchers/ToolWatcher.js +71 -0
- package/dist/watchers/ToolWatcher.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { NullLogger } from "../logger/NullLogger.js";
|
|
2
|
+
const ABSOLUTE_MAX_HISTORY_SIZE = 10000;
|
|
3
|
+
class HistoryManager {
|
|
4
|
+
static DEFAULT_SESSION = '__global__';
|
|
5
|
+
static SESSION_TTL_MS = 1800000;
|
|
6
|
+
static MAX_SESSIONS = 100;
|
|
7
|
+
_sessions = new Map();
|
|
8
|
+
_sessionCleanupTimer = null;
|
|
9
|
+
_maxHistorySize;
|
|
10
|
+
_maxBranches;
|
|
11
|
+
_maxBranchSize;
|
|
12
|
+
_logger;
|
|
13
|
+
_persistence;
|
|
14
|
+
_persistenceEnabled;
|
|
15
|
+
_metrics;
|
|
16
|
+
_flushTimer = null;
|
|
17
|
+
_isFlushing = false;
|
|
18
|
+
_flushRetryCount = 0;
|
|
19
|
+
_persistenceBufferSize;
|
|
20
|
+
_persistenceFlushInterval;
|
|
21
|
+
_persistenceMaxRetries;
|
|
22
|
+
_eventEmitter;
|
|
23
|
+
constructor(config = {}){
|
|
24
|
+
this._logger = config.logger ?? new NullLogger();
|
|
25
|
+
const requestedMaxSize = config.maxHistorySize ?? 1000;
|
|
26
|
+
this._maxHistorySize = Math.min(requestedMaxSize, ABSOLUTE_MAX_HISTORY_SIZE);
|
|
27
|
+
if (requestedMaxSize > ABSOLUTE_MAX_HISTORY_SIZE) this._logger.warn('maxHistorySize exceeds absolute maximum, capped', {
|
|
28
|
+
requested: requestedMaxSize,
|
|
29
|
+
applied: ABSOLUTE_MAX_HISTORY_SIZE
|
|
30
|
+
});
|
|
31
|
+
this._maxBranches = config.maxBranches || 50;
|
|
32
|
+
this._maxBranchSize = config.maxBranchSize || 100;
|
|
33
|
+
this._persistence = config.persistence ?? null;
|
|
34
|
+
this._persistenceEnabled = null !== this._persistence;
|
|
35
|
+
this._metrics = config.metrics;
|
|
36
|
+
this._persistenceBufferSize = config.persistenceBufferSize ?? 100;
|
|
37
|
+
this._persistenceFlushInterval = config.persistenceFlushInterval ?? 1000;
|
|
38
|
+
this._persistenceMaxRetries = config.persistenceMaxRetries ?? 3;
|
|
39
|
+
this._eventEmitter = config.eventEmitter ?? null;
|
|
40
|
+
if (this._persistenceEnabled) this._startFlushTimer();
|
|
41
|
+
this._startSessionCleanupTimer();
|
|
42
|
+
}
|
|
43
|
+
log(message, meta) {
|
|
44
|
+
this._logger.info(message, meta);
|
|
45
|
+
}
|
|
46
|
+
_getSession(sessionId) {
|
|
47
|
+
const key = sessionId ?? HistoryManager.DEFAULT_SESSION;
|
|
48
|
+
let session = this._sessions.get(key);
|
|
49
|
+
if (!session) {
|
|
50
|
+
session = {
|
|
51
|
+
thought_history: [],
|
|
52
|
+
branches: {},
|
|
53
|
+
availableMcpTools: void 0,
|
|
54
|
+
availableSkills: void 0,
|
|
55
|
+
writeBuffer: [],
|
|
56
|
+
lastAccessedAt: Date.now()
|
|
57
|
+
};
|
|
58
|
+
this._sessions.set(key, session);
|
|
59
|
+
this._evictExcessSessions();
|
|
60
|
+
}
|
|
61
|
+
session.lastAccessedAt = Date.now();
|
|
62
|
+
return session;
|
|
63
|
+
}
|
|
64
|
+
addThought(thought) {
|
|
65
|
+
const session = this._getSession(thought.session_id);
|
|
66
|
+
this._metrics?.counter('thought_requests_total', 1, {}, 'Total thought requests added to history');
|
|
67
|
+
session.thought_history.push(thought);
|
|
68
|
+
if (thought.available_mcp_tools) session.availableMcpTools = thought.available_mcp_tools;
|
|
69
|
+
if (thought.available_skills) session.availableSkills = thought.available_skills;
|
|
70
|
+
if (session.thought_history.length > this._maxHistorySize) {
|
|
71
|
+
session.thought_history = session.thought_history.slice(-this._maxHistorySize);
|
|
72
|
+
this.log(`History trimmed to ${this._maxHistorySize} items`, {
|
|
73
|
+
maxSize: this._maxHistorySize
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (thought.branch_from_thought && thought.branch_id) this._addToSessionBranch(session, thought.branch_id, thought);
|
|
77
|
+
if (thought.merge_from_thoughts?.length || thought.merge_branch_ids?.length) this._metrics?.counter('thought_merge_operations_total', 1, {}, 'Total merge operations (graph topology)');
|
|
78
|
+
this._bufferForPersistence(session, thought);
|
|
79
|
+
}
|
|
80
|
+
_bufferForPersistence(session, thought) {
|
|
81
|
+
if (!this._persistenceEnabled || !this._persistence) return;
|
|
82
|
+
if (session.writeBuffer.length >= this._persistenceBufferSize && this._isFlushing) this.log('Write buffer full and flush in progress, applying backpressure', {
|
|
83
|
+
bufferSize: session.writeBuffer.length,
|
|
84
|
+
maxSize: this._persistenceBufferSize
|
|
85
|
+
});
|
|
86
|
+
session.writeBuffer.push(thought);
|
|
87
|
+
if (session.writeBuffer.length >= this._persistenceBufferSize) this._flushBuffer();
|
|
88
|
+
}
|
|
89
|
+
_addToSessionBranch(session, branchId, thought) {
|
|
90
|
+
if (!session.branches[branchId]) session.branches[branchId] = [];
|
|
91
|
+
this._trimSessionBranchSize(session, branchId);
|
|
92
|
+
session.branches[branchId].push(thought);
|
|
93
|
+
if (Object.keys(session.branches).length > this._maxBranches) this._cleanupSessionBranches(session);
|
|
94
|
+
if (this._persistenceEnabled && this._persistence) this._persistence.saveBranch(branchId, session.branches[branchId]).catch((err)=>{
|
|
95
|
+
this.log('Failed to persist branch', {
|
|
96
|
+
branchId,
|
|
97
|
+
error: err instanceof Error ? err.message : String(err)
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
_cleanupSessionBranches(session) {
|
|
102
|
+
const branchCount = Object.keys(session.branches).length;
|
|
103
|
+
if (branchCount > this._maxBranches) {
|
|
104
|
+
const branchesToRemove = Object.keys(session.branches).slice(0, branchCount - this._maxBranches);
|
|
105
|
+
for (const branchId of branchesToRemove){
|
|
106
|
+
delete session.branches[branchId];
|
|
107
|
+
this.log(`Removed old branch: ${branchId}`, {
|
|
108
|
+
branchId
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
_trimSessionBranchSize(session, branchId) {
|
|
114
|
+
if ((session.branches[branchId] ?? []).length > this._maxBranchSize) {
|
|
115
|
+
const removed = session.branches[branchId].length - this._maxBranchSize;
|
|
116
|
+
session.branches[branchId] = session.branches[branchId].slice(-this._maxBranchSize);
|
|
117
|
+
this.log(`Trimmed branch '${branchId}': removed ${removed} old thoughts`, {
|
|
118
|
+
branchId,
|
|
119
|
+
removed
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
getHistory(sessionId) {
|
|
124
|
+
return this._getSession(sessionId).thought_history;
|
|
125
|
+
}
|
|
126
|
+
getHistoryLength(sessionId) {
|
|
127
|
+
return this._getSession(sessionId).thought_history.length;
|
|
128
|
+
}
|
|
129
|
+
getBranches(sessionId) {
|
|
130
|
+
return this._getSession(sessionId).branches;
|
|
131
|
+
}
|
|
132
|
+
getBranchIds(sessionId) {
|
|
133
|
+
return Object.keys(this._getSession(sessionId).branches);
|
|
134
|
+
}
|
|
135
|
+
getAvailableMcpTools(sessionId) {
|
|
136
|
+
return this._getSession(sessionId).availableMcpTools;
|
|
137
|
+
}
|
|
138
|
+
getAvailableSkills(sessionId) {
|
|
139
|
+
return this._getSession(sessionId).availableSkills;
|
|
140
|
+
}
|
|
141
|
+
getBranch(branchId, sessionId) {
|
|
142
|
+
return this._getSession(sessionId).branches[branchId];
|
|
143
|
+
}
|
|
144
|
+
clear(sessionId) {
|
|
145
|
+
if (void 0 !== sessionId) {
|
|
146
|
+
this._sessions.delete(sessionId);
|
|
147
|
+
this.log('Session cleared', {
|
|
148
|
+
sessionId
|
|
149
|
+
});
|
|
150
|
+
} else {
|
|
151
|
+
this._sessions.clear();
|
|
152
|
+
this.log('History cleared (all sessions)');
|
|
153
|
+
}
|
|
154
|
+
if (this._persistenceEnabled && this._persistence) this._persistence.clear().catch((err)=>{
|
|
155
|
+
this.log('Failed to clear persisted data', {
|
|
156
|
+
error: err instanceof Error ? err.message : String(err)
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
clearSession(sessionId) {
|
|
161
|
+
this.clear(sessionId);
|
|
162
|
+
}
|
|
163
|
+
getSessionIds() {
|
|
164
|
+
return Array.from(this._sessions.keys());
|
|
165
|
+
}
|
|
166
|
+
getSessionCount() {
|
|
167
|
+
return this._sessions.size;
|
|
168
|
+
}
|
|
169
|
+
async loadFromPersistence() {
|
|
170
|
+
if (!this._persistenceEnabled || !this._persistence) return;
|
|
171
|
+
try {
|
|
172
|
+
const isHealthy = await this._persistence.healthy();
|
|
173
|
+
if (!isHealthy) return void this.log('Persistence backend not healthy, skipping load');
|
|
174
|
+
const globalSession = this._getSession();
|
|
175
|
+
const history = await this._persistence.loadHistory();
|
|
176
|
+
if (history.length > 0) {
|
|
177
|
+
globalSession.thought_history = history.slice(-this._maxHistorySize);
|
|
178
|
+
this.log(`Loaded ${globalSession.thought_history.length} thoughts from persistence`);
|
|
179
|
+
}
|
|
180
|
+
const branchIds = await this._persistence.listBranches();
|
|
181
|
+
for (const branchId of branchIds){
|
|
182
|
+
const branchData = await this._persistence.loadBranch(branchId);
|
|
183
|
+
if (branchData) globalSession.branches[branchId] = branchData.slice(-this._maxBranchSize);
|
|
184
|
+
}
|
|
185
|
+
this.log(`Loaded ${Object.keys(globalSession.branches).length} branches from persistence`);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
this.log('Failed to load from persistence', {
|
|
188
|
+
error: error instanceof Error ? error.message : String(error)
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
isPersistenceEnabled() {
|
|
193
|
+
return this._persistenceEnabled;
|
|
194
|
+
}
|
|
195
|
+
getPersistenceBackend() {
|
|
196
|
+
return this._persistence;
|
|
197
|
+
}
|
|
198
|
+
setEventEmitter(emitter) {
|
|
199
|
+
this._eventEmitter = emitter;
|
|
200
|
+
}
|
|
201
|
+
async shutdown() {
|
|
202
|
+
this._stopFlushTimer();
|
|
203
|
+
this._stopSessionCleanupTimer();
|
|
204
|
+
await this._flushBuffer();
|
|
205
|
+
}
|
|
206
|
+
_startFlushTimer() {
|
|
207
|
+
if (null !== this._flushTimer) return;
|
|
208
|
+
this._flushTimer = setInterval(()=>{
|
|
209
|
+
this._flushBuffer();
|
|
210
|
+
}, this._persistenceFlushInterval);
|
|
211
|
+
if (this._flushTimer && 'object' == typeof this._flushTimer && 'unref' in this._flushTimer) this._flushTimer.unref();
|
|
212
|
+
}
|
|
213
|
+
_stopFlushTimer() {
|
|
214
|
+
if (null !== this._flushTimer) {
|
|
215
|
+
clearInterval(this._flushTimer);
|
|
216
|
+
this._flushTimer = null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
_startSessionCleanupTimer() {
|
|
220
|
+
if (null !== this._sessionCleanupTimer) return;
|
|
221
|
+
this._sessionCleanupTimer = setInterval(()=>{
|
|
222
|
+
this._cleanupStaleSessions();
|
|
223
|
+
}, 300000);
|
|
224
|
+
if (this._sessionCleanupTimer && 'object' == typeof this._sessionCleanupTimer && 'unref' in this._sessionCleanupTimer) this._sessionCleanupTimer.unref();
|
|
225
|
+
}
|
|
226
|
+
_stopSessionCleanupTimer() {
|
|
227
|
+
if (null !== this._sessionCleanupTimer) {
|
|
228
|
+
clearInterval(this._sessionCleanupTimer);
|
|
229
|
+
this._sessionCleanupTimer = null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
_cleanupStaleSessions() {
|
|
233
|
+
const now = Date.now();
|
|
234
|
+
for (const [key, session] of this._sessions)if (key !== HistoryManager.DEFAULT_SESSION) {
|
|
235
|
+
if (now - session.lastAccessedAt > HistoryManager.SESSION_TTL_MS) {
|
|
236
|
+
this._sessions.delete(key);
|
|
237
|
+
this.log('Evicted stale session', {
|
|
238
|
+
sessionId: key
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
_evictExcessSessions() {
|
|
244
|
+
while(this._sessions.size > HistoryManager.MAX_SESSIONS){
|
|
245
|
+
let oldestKey = null;
|
|
246
|
+
let oldestTime = 1 / 0;
|
|
247
|
+
for (const [key, session] of this._sessions)if (key !== HistoryManager.DEFAULT_SESSION) {
|
|
248
|
+
if (session.lastAccessedAt < oldestTime) {
|
|
249
|
+
oldestTime = session.lastAccessedAt;
|
|
250
|
+
oldestKey = key;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (null !== oldestKey) {
|
|
254
|
+
this._sessions.delete(oldestKey);
|
|
255
|
+
this.log('Evicted oldest session (LRU)', {
|
|
256
|
+
sessionId: oldestKey
|
|
257
|
+
});
|
|
258
|
+
} else break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async _flushBuffer() {
|
|
262
|
+
if (this._isFlushing || !this._persistence) return;
|
|
263
|
+
const allPending = [];
|
|
264
|
+
for (const session of this._sessions.values())if (session.writeBuffer.length > 0) allPending.push(...session.writeBuffer.splice(0));
|
|
265
|
+
if (0 === allPending.length) return;
|
|
266
|
+
this._isFlushing = true;
|
|
267
|
+
const failedItems = [];
|
|
268
|
+
try {
|
|
269
|
+
for (const thought of allPending){
|
|
270
|
+
const saved = await this._flushSingleThought(thought);
|
|
271
|
+
if (!saved) failedItems.push(thought);
|
|
272
|
+
}
|
|
273
|
+
this._handleFlushResult(failedItems, allPending.length);
|
|
274
|
+
} finally{
|
|
275
|
+
this._isFlushing = false;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
async _flushSingleThought(thought) {
|
|
279
|
+
const backoffDelays = [
|
|
280
|
+
100,
|
|
281
|
+
500,
|
|
282
|
+
2000
|
|
283
|
+
];
|
|
284
|
+
for(let attempt = 0; attempt <= this._persistenceMaxRetries; attempt++)try {
|
|
285
|
+
await this._persistence.saveThought(thought);
|
|
286
|
+
return true;
|
|
287
|
+
} catch (err) {
|
|
288
|
+
if (attempt < this._persistenceMaxRetries) {
|
|
289
|
+
const delay = backoffDelays[attempt] ?? backoffDelays[backoffDelays.length - 1];
|
|
290
|
+
this.log(`Persistence retry ${attempt + 1}/${this._persistenceMaxRetries}`, {
|
|
291
|
+
thoughtNumber: thought.thought_number,
|
|
292
|
+
delay,
|
|
293
|
+
error: err instanceof Error ? err.message : String(err)
|
|
294
|
+
});
|
|
295
|
+
await this._delay(delay);
|
|
296
|
+
} else this.log('All persistence retries exhausted for thought', {
|
|
297
|
+
thoughtNumber: thought.thought_number,
|
|
298
|
+
error: err instanceof Error ? err.message : String(err)
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
_handleFlushResult(failedItems, totalCount) {
|
|
304
|
+
if (failedItems.length > 0) {
|
|
305
|
+
const globalSession = this._getSession();
|
|
306
|
+
globalSession.writeBuffer.unshift(...failedItems);
|
|
307
|
+
this._flushRetryCount++;
|
|
308
|
+
const error = new Error(`Failed to persist ${failedItems.length} thoughts after ${this._persistenceMaxRetries} retries`);
|
|
309
|
+
this._eventEmitter?.emit('persistenceError', {
|
|
310
|
+
operation: 'flushBuffer',
|
|
311
|
+
error
|
|
312
|
+
});
|
|
313
|
+
this.log('Flush completed with failures', {
|
|
314
|
+
failed: failedItems.length,
|
|
315
|
+
total: totalCount,
|
|
316
|
+
consecutiveFailures: this._flushRetryCount
|
|
317
|
+
});
|
|
318
|
+
} else this._flushRetryCount = 0;
|
|
319
|
+
}
|
|
320
|
+
_delay(ms) {
|
|
321
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
322
|
+
}
|
|
323
|
+
getWriteBufferLength() {
|
|
324
|
+
let total = 0;
|
|
325
|
+
for (const session of this._sessions.values())total += session.writeBuffer.length;
|
|
326
|
+
return total;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
export { ABSOLUTE_MAX_HISTORY_SIZE, HistoryManager };
|
|
330
|
+
|
|
331
|
+
//# sourceMappingURL=HistoryManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core/HistoryManager.js","sources":["../../src/core/HistoryManager.ts"],"sourcesContent":["/**\n * History and branch management for sequential thinking.\n *\n * This module provides the `HistoryManager` class which manages thought history,\n * branching, and optional persistence with per-session state isolation.\n *\n * @module HistoryManager\n */\n\nimport type { IMetrics } from '../contracts/index.js';\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { PersistenceBackend } from '../persistence/PersistenceBackend.js';\nimport type { IHistoryManager } from './IHistoryManager.js';\nimport type { ThoughtData } from './thought.js';\n\n/**\n * Absolute maximum history size. Cannot be overridden by configuration.\n * Prevents unbounded memory growth from misconfiguration.\n * At ~2KB per thought, 10K thoughts ≈ ~20MB — reasonable for server-side.\n * @constant\n */\nexport const ABSOLUTE_MAX_HISTORY_SIZE = 10_000;\n\n/**\n * Interface for emitting persistence error events.\n * Compatible with EventEmitter's emit method signature.\n */\nexport interface PersistenceEventEmitter {\n\temit(event: 'persistenceError', payload: { operation: string; error: Error }): boolean;\n}\n\n/** Internal state container for a single session's data. */\ninterface SessionState {\n\tthought_history: ThoughtData[];\n\tbranches: Record<string, ThoughtData[]>;\n\tavailableMcpTools: string[] | undefined;\n\tavailableSkills: string[] | undefined;\n\twriteBuffer: ThoughtData[];\n\tlastAccessedAt: number;\n}\n\n/**\n * Configuration options for creating a `HistoryManager` instance.\n *\n * @example\n * ```typescript\n * const config: HistoryManagerConfig = {\n * maxHistorySize: 500,\n * maxBranches: 25,\n * maxBranchSize: 50,\n * logger: new StructuredLogger(),\n * persistence: filePersistence\n * };\n * ```\n */\nexport interface HistoryManagerConfig {\n\t/**\n\t * Maximum number of thoughts to keep in main history.\n\t * @default 1000\n\t */\n\tmaxHistorySize?: number;\n\n\t/**\n\t * Maximum number of branches to maintain.\n\t * @default 50\n\t */\n\tmaxBranches?: number;\n\n\t/**\n\t * Maximum size of each branch.\n\t * @default 100\n\t */\n\tmaxBranchSize?: number;\n\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional persistence backend for saving/loading history. */\n\tpersistence?: PersistenceBackend | null;\n\tmetrics?: IMetrics;\n\n\t/**\n\t * Maximum number of thoughts to buffer before flushing to persistence.\n\t * @default 100\n\t */\n\tpersistenceBufferSize?: number;\n\n\t/**\n\t * Interval in milliseconds between periodic persistence flushes.\n\t * @default 1000\n\t */\n\tpersistenceFlushInterval?: number;\n\n\t/**\n\t * Maximum number of retries for failed persistence flushes.\n\t * @default 3\n\t */\n\tpersistenceMaxRetries?: number;\n\n\t/**\n\t * Event emitter for persistence error events.\n\t * When provided, persistenceError events are emitted on persistent failures.\n\t */\n\teventEmitter?: PersistenceEventEmitter;\n}\n\n/**\n * Manages thought history and branching for sequential thinking.\n *\n * This class is the central component for managing the state of sequential thinking\n * operations. It handles thought storage, branch management, and optional persistence\n * for state recovery. State is isolated per session via a `Map<string, SessionState>`.\n *\n * @remarks\n * **History Management:**\n * - Thoughts are stored in a linear history array per session\n * - Auto-trimming occurs when `maxHistorySize` is exceeded\n * - Oldest thoughts are removed first (FIFO eviction)\n *\n * **Session Isolation:**\n * - Each session maintains its own thought history, branches, and cached tools/skills\n * - Sessions are identified by optional `session_id` on ThoughtData\n * - Default (undefined) session_id maps to `__global__`\n * - TTL-based cleanup prevents unbounded memory growth\n * - LRU eviction when MAX_SESSIONS exceeded\n *\n * **Branch Management:**\n * - Branches allow exploring alternative reasoning paths\n * - Each branch has its own thought array within a session\n * - Branches are created when `branch_from_thought` and `branch_id` are set\n * - Branch count and size are limited by `maxBranches` and `maxBranchSize`\n *\n * **Persistence:**\n * - Optional persistence backend for saving/loading state\n * - Persists thoughts and branches asynchronously (fire-and-forget)\n * - Does not block on persistence failures\n *\n * @example\n * ```typescript\n * const manager = new HistoryManager({\n * maxHistorySize: 500,\n * maxBranches: 25,\n * logger: new StructuredLogger({ context: 'History' })\n * });\n *\n * // Add a thought\n * manager.addThought({\n * thought: 'I need to analyze the problem',\n * thought_number: 1,\n * total_thoughts: 5,\n * next_thought_needed: true\n * });\n *\n * // Get history\n * const history = manager.getHistory();\n * console.log(`Thoughts: ${history.length}`);\n *\n * // Get branches\n * const branches = manager.getBranches();\n * console.log(`Branches: ${Object.keys(branches).length}`);\n *\n * // Clear all state\n * manager.clear();\n * ```\n */\nexport class HistoryManager implements IHistoryManager {\n\t/** Default session key for backward-compatible global state. */\n\tprivate static readonly DEFAULT_SESSION = '__global__';\n\n\t/** TTL for inactive sessions in milliseconds (default: 30 minutes). */\n\tprivate static readonly SESSION_TTL_MS = 30 * 60 * 1000;\n\n\t/** Maximum number of concurrent sessions before eviction. */\n\tprivate static readonly MAX_SESSIONS = 100;\n\n\t/** Session state storage. */\n\tprivate _sessions: Map<string, SessionState> = new Map();\n\n\t/** Timer for periodic session cleanup. */\n\tprivate _sessionCleanupTimer: ReturnType<typeof setInterval> | null = null;\n\n\t/** Maximum history size before auto-trimming. */\n\tprivate _maxHistorySize: number;\n\n\t/** Maximum number of branches before cleanup. */\n\tprivate _maxBranches: number;\n\n\t/** Maximum size of each branch. */\n\tprivate _maxBranchSize: number;\n\n\t/** Logger for diagnostics. */\n\tprivate _logger: Logger;\n\n\t/** Persistence backend for saving/loading state. */\n\tprivate _persistence: PersistenceBackend | null;\n\n\t/** Whether persistence is enabled. */\n\tprivate _persistenceEnabled: boolean;\n\n\tprivate _metrics?: IMetrics;\n\n\t/** Timer for periodic buffer flushes. */\n\tprivate _flushTimer: ReturnType<typeof setInterval> | null = null;\n\n\t/** Guard to prevent concurrent flushes. */\n\tprivate _isFlushing: boolean = false;\n\n\t/** Tracks consecutive flush failures for backoff. */\n\tprivate _flushRetryCount: number = 0;\n\n\t/** Maximum buffer size before triggering immediate flush. */\n\tprivate _persistenceBufferSize: number;\n\n\t/** Interval in milliseconds between periodic flushes. */\n\tprivate _persistenceFlushInterval: number;\n\n\t/** Maximum number of retries for failed flushes. */\n\tprivate _persistenceMaxRetries: number;\n\n\t/** Event emitter for persistence error events. */\n\tprivate _eventEmitter: PersistenceEventEmitter | null;\n\n\t/**\n\t * Creates a new HistoryManager instance.\n\t *\n\t * @param config - Configuration options for the history manager\n\t *\n\t * @example\n\t * ```typescript\n\t * const manager = new HistoryManager({\n\t * maxHistorySize: 500,\n\t * maxBranches: 25,\n\t * logger: new StructuredLogger(),\n\t * persistence: filePersistence\n\t * });\n\t * ```\n\t */\n\tconstructor(config: HistoryManagerConfig = {}) {\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t\tconst requestedMaxSize = config.maxHistorySize ?? 1000;\n\t\tthis._maxHistorySize = Math.min(requestedMaxSize, ABSOLUTE_MAX_HISTORY_SIZE);\n\t\tif (requestedMaxSize > ABSOLUTE_MAX_HISTORY_SIZE) {\n\t\t\tthis._logger.warn('maxHistorySize exceeds absolute maximum, capped', {\n\t\t\t\trequested: requestedMaxSize,\n\t\t\t\tapplied: ABSOLUTE_MAX_HISTORY_SIZE,\n\t\t\t});\n\t\t}\n\t\tthis._maxBranches = config.maxBranches || 50;\n\t\tthis._maxBranchSize = config.maxBranchSize || 100;\n\t\tthis._persistence = config.persistence ?? null;\n\t\tthis._persistenceEnabled = this._persistence !== null;\n\t\tthis._metrics = config.metrics;\n\t\tthis._persistenceBufferSize = config.persistenceBufferSize ?? 100;\n\t\tthis._persistenceFlushInterval = config.persistenceFlushInterval ?? 1000;\n\t\tthis._persistenceMaxRetries = config.persistenceMaxRetries ?? 3;\n\t\tthis._eventEmitter = config.eventEmitter ?? null;\n\n\t\t// Start the periodic flush timer if persistence is enabled\n\t\tif (this._persistenceEnabled) {\n\t\t\tthis._startFlushTimer();\n\t\t}\n\n\t\t// Start the periodic session cleanup timer\n\t\tthis._startSessionCleanupTimer();\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 * Gets or creates the session state for a given session ID.\n\t * Creates a new SessionState if one doesn't exist.\n\t * Updates lastAccessedAt on every access.\n\t *\n\t * @param sessionId - Optional session ID (defaults to `__global__`)\n\t * @returns The session state\n\t * @private\n\t */\n\tprivate _getSession(sessionId?: string): SessionState {\n\t\tconst key = sessionId ?? HistoryManager.DEFAULT_SESSION;\n\t\tlet session = this._sessions.get(key);\n\t\tif (!session) {\n\t\t\tsession = {\n\t\t\t\tthought_history: [],\n\t\t\t\tbranches: {},\n\t\t\t\tavailableMcpTools: undefined,\n\t\t\t\tavailableSkills: undefined,\n\t\t\t\twriteBuffer: [],\n\t\t\t\tlastAccessedAt: Date.now(),\n\t\t\t};\n\t\t\tthis._sessions.set(key, session);\n\t\t\tthis._evictExcessSessions();\n\t\t}\n\t\tsession.lastAccessedAt = Date.now();\n\t\treturn session;\n\t}\n\n\t/**\n\t * Adds a thought to the history.\n\t *\n\t * The thought is appended to the session's history array. If history exceeds\n\t * `maxHistorySize`, the oldest thoughts are removed. If the thought\n\t * has `branch_from_thought` and `branch_id` set, it's also added to\n\t * the appropriate branch. The thought is persisted asynchronously if\n\t * persistence is enabled.\n\t *\n\t * @param thought - The thought data to add\n\t *\n\t * @example\n\t * ```typescript\n\t * manager.addThought({\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 */\n\tpublic addThought(thought: ThoughtData): void {\n\t\tconst session = this._getSession(thought.session_id);\n\t\tthis._metrics?.counter(\n\t\t\t'thought_requests_total',\n\t\t\t1,\n\t\t\t{},\n\t\t\t'Total thought requests added to history'\n\t\t);\n\n\t\tsession.thought_history.push(thought);\n\n\t\t// Cache available_mcp_tools/available_skills for cross-call persistence\n\t\tif (thought.available_mcp_tools) {\n\t\t\tsession.availableMcpTools = thought.available_mcp_tools;\n\t\t}\n\t\tif (thought.available_skills) {\n\t\t\tsession.availableSkills = thought.available_skills;\n\t\t}\n\n\t\tif (session.thought_history.length > this._maxHistorySize) {\n\t\t\tsession.thought_history = session.thought_history.slice(-this._maxHistorySize);\n\t\t\tthis.log(`History trimmed to ${this._maxHistorySize} items`, {\n\t\t\t\tmaxSize: this._maxHistorySize,\n\t\t\t});\n\t\t}\n\n\t\tif (thought.branch_from_thought && thought.branch_id) {\n\t\t\tthis._addToSessionBranch(session, thought.branch_id, thought);\n\t\t}\n\n\t\t// Track merge operations for analytics\n\t\tif (thought.merge_from_thoughts?.length || thought.merge_branch_ids?.length) {\n\t\t\tthis._metrics?.counter(\n\t\t\t\t'thought_merge_operations_total',\n\t\t\t\t1,\n\t\t\t\t{},\n\t\t\t\t'Total merge operations (graph topology)'\n\t\t\t);\n\t\t}\n\n\t\t// Buffer thought for persistence instead of fire-and-forget\n\t\tthis._bufferForPersistence(session, thought);\n\t}\n\n\t/**\n\t * Buffers a thought for persistence if enabled.\n\t * @param session - The session state to buffer into\n\t * @param thought - The thought to buffer\n\t * @private\n\t */\n\tprivate _bufferForPersistence(session: SessionState, thought: ThoughtData): void {\n\t\tif (!this._persistenceEnabled || !this._persistence) return;\n\n\t\t// Backpressure: if buffer is full and flush is failing, log warning\n\t\tif (session.writeBuffer.length >= this._persistenceBufferSize && this._isFlushing) {\n\t\t\tthis.log('Write buffer full and flush in progress, applying backpressure', {\n\t\t\t\tbufferSize: session.writeBuffer.length,\n\t\t\t\tmaxSize: this._persistenceBufferSize,\n\t\t\t});\n\t\t}\n\n\t\tsession.writeBuffer.push(thought);\n\n\t\t// Trigger immediate flush if buffer is at capacity\n\t\tif (session.writeBuffer.length >= this._persistenceBufferSize) {\n\t\t\tvoid this._flushBuffer();\n\t\t}\n\t}\n\n\t/**\n\t * Adds a thought to a branch within a specific session.\n\t * @param session - The session state\n\t * @param branchId - The branch identifier\n\t * @param thought - The thought data to add\n\t * @private\n\t */\n\tprivate _addToSessionBranch(session: SessionState, branchId: string, thought: ThoughtData): void {\n\t\tif (!session.branches[branchId]) {\n\t\t\tsession.branches[branchId] = [];\n\t\t}\n\t\tthis._trimSessionBranchSize(session, branchId);\n\t\tsession.branches[branchId].push(thought);\n\n\t\tif (Object.keys(session.branches).length > this._maxBranches) {\n\t\t\tthis._cleanupSessionBranches(session);\n\t\t}\n\n\t\t// Persist branch to backend if enabled\n\t\tif (this._persistenceEnabled && this._persistence) {\n\t\t\tthis._persistence.saveBranch(branchId, session.branches[branchId]).catch((err) => {\n\t\t\t\tthis.log('Failed to persist branch', {\n\t\t\t\t\tbranchId,\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Removes old branches when count exceeds maxBranches within a session.\n\t * @param session - The session state\n\t * @private\n\t */\n\tprivate _cleanupSessionBranches(session: SessionState): void {\n\t\tconst branchCount = Object.keys(session.branches).length;\n\t\tif (branchCount > this._maxBranches) {\n\t\t\tconst branchesToRemove = Object.keys(session.branches).slice(\n\t\t\t\t0,\n\t\t\t\tbranchCount - this._maxBranches\n\t\t\t);\n\t\t\tfor (const branchId of branchesToRemove) {\n\t\t\t\tdelete session.branches[branchId];\n\t\t\t\tthis.log(`Removed old branch: ${branchId}`, { branchId });\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Trims a branch to maxBranchSize within a session.\n\t * @param session - The session state\n\t * @param branchId - The branch identifier to trim\n\t * @private\n\t */\n\tprivate _trimSessionBranchSize(session: SessionState, branchId: string): void {\n\t\tif ((session.branches[branchId] ?? []).length > this._maxBranchSize) {\n\t\t\tconst removed = session.branches[branchId]!.length - this._maxBranchSize;\n\t\t\tsession.branches[branchId] = session.branches[branchId]!.slice(-this._maxBranchSize);\n\t\t\tthis.log(`Trimmed branch '${branchId}': removed ${removed} old thoughts`, {\n\t\t\t\tbranchId,\n\t\t\t\tremoved,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Gets the complete thought history.\n\t *\n\t * @param sessionId - Optional session ID for session-scoped results\n\t * @returns An array of all thoughts in chronological order\n\t *\n\t * @example\n\t * ```typescript\n\t * const history = manager.getHistory();\n\t * history.forEach(thought => {\n\t * console.log(`${thought.thought_number}: ${thought.thought}`);\n\t * });\n\t * ```\n\t */\n\tpublic getHistory(sessionId?: string): ThoughtData[] {\n\t\treturn this._getSession(sessionId).thought_history;\n\t}\n\n\t/**\n\t * Gets the current length of the thought history.\n\t *\n\t * @param sessionId - Optional session ID for session-scoped results\n\t * @returns The number of thoughts in history\n\t *\n\t * @example\n\t * ```typescript\n\t * console.log(`Total thoughts: ${manager.getHistoryLength()}`);\n\t * ```\n\t */\n\tpublic getHistoryLength(sessionId?: string): number {\n\t\treturn this._getSession(sessionId).thought_history.length;\n\t}\n\n\t/**\n\t * Gets all branches.\n\t *\n\t * @param sessionId - Optional session ID for session-scoped results\n\t * @returns A record mapping branch IDs to their thought arrays\n\t *\n\t * @example\n\t * ```typescript\n\t * const branches = manager.getBranches();\n\t * for (const [branchId, thoughts] of Object.entries(branches)) {\n\t * console.log(`Branch ${branchId}: ${thoughts.length} thoughts`);\n\t * }\n\t * ```\n\t */\n\tpublic getBranches(sessionId?: string): Record<string, ThoughtData[]> {\n\t\treturn this._getSession(sessionId).branches;\n\t}\n\n\t/**\n\t * Gets all branch IDs.\n\t *\n\t * @param sessionId - Optional session ID for session-scoped results\n\t * @returns An array of branch identifiers\n\t *\n\t * @example\n\t * ```typescript\n\t * const branchIds = manager.getBranchIds();\n\t * console.log(`Active branches: ${branchIds.join(', ')}`);\n\t * ```\n\t */\n\tpublic getBranchIds(sessionId?: string): string[] {\n\t\treturn Object.keys(this._getSession(sessionId).branches);\n\t}\n\n\t/**\n\t * Gets the most recently available MCP tools from the session.\n\t *\n\t * @param sessionId - Optional session ID for session-scoped results\n\t * @returns The last-seen array of MCP tool names, or undefined if never set\n\t *\n\t * @example\n\t * ```typescript\n\t * const tools = manager.getAvailableMcpTools();\n\t * // ['Read', 'Grep', 'Glob'] or undefined\n\t * ```\n\t */\n\tpublic getAvailableMcpTools(sessionId?: string): string[] | undefined {\n\t\treturn this._getSession(sessionId).availableMcpTools;\n\t}\n\n\t/**\n\t * Gets the most recently available skills from the session.\n\t *\n\t * @param sessionId - Optional session ID for session-scoped results\n\t * @returns The last-seen array of skill names, or undefined if never set\n\t *\n\t * @example\n\t * ```typescript\n\t * const skills = manager.getAvailableSkills();\n\t * // ['commit', 'review-pr'] or undefined\n\t * ```\n\t */\n\tpublic getAvailableSkills(sessionId?: string): string[] | undefined {\n\t\treturn this._getSession(sessionId).availableSkills;\n\t}\n\n\t/**\n\t * Gets a specific branch by ID.\n\t *\n\t * @param branchId - The branch identifier\n\t * @param sessionId - Optional session ID for session-scoped results\n\t * @returns The branch's thought array, or undefined if not found\n\t *\n\t * @example\n\t * ```typescript\n\t * const branch = manager.getBranch('alternative-approach');\n\t * if (branch) {\n\t * console.log(`Branch has ${branch.length} thoughts`);\n\t * } else {\n\t * console.log('Branch not found');\n\t * }\n\t * ```\n\t */\n\tpublic getBranch(branchId: string, sessionId?: string): ThoughtData[] | undefined {\n\t\treturn this._getSession(sessionId).branches[branchId];\n\t}\n\n\t/**\n\t * Clears history and branches.\n\t * If sessionId is provided, clears only that session.\n\t * If omitted, clears all sessions.\n\t *\n\t * @param sessionId - Optional session ID to clear\n\t *\n\t * @example\n\t * ```typescript\n\t * manager.clear();\n\t * console.log('All history and branches cleared');\n\t * ```\n\t */\n\tpublic clear(sessionId?: string): void {\n\t\tif (sessionId !== undefined) {\n\t\t\t// Clear specific session\n\t\t\tthis._sessions.delete(sessionId);\n\t\t\tthis.log('Session cleared', { sessionId });\n\t\t} else {\n\t\t\t// Clear all sessions\n\t\t\tthis._sessions.clear();\n\t\t\tthis.log('History cleared (all sessions)');\n\t\t}\n\n\t\t// Clear persisted data if enabled\n\t\tif (this._persistenceEnabled && this._persistence) {\n\t\t\tthis._persistence.clear().catch((err) => {\n\t\t\t\tthis.log('Failed to clear persisted data', {\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\t/** Clears state for a specific session. Alias for clear(sessionId). */\n\tpublic clearSession(sessionId: string): void {\n\t\tthis.clear(sessionId);\n\t}\n\n\t/** Gets all active session IDs. */\n\tpublic getSessionIds(): string[] {\n\t\treturn Array.from(this._sessions.keys());\n\t}\n\n\t/** Gets the number of active sessions. */\n\tpublic getSessionCount(): number {\n\t\treturn this._sessions.size;\n\t}\n\n\t/**\n\t * Loads history from the persistence backend.\n\t *\n\t * This should be called during initialization to restore previous state.\n\t * Only loads if persistence is enabled and the backend is healthy.\n\t * Loads into the global session.\n\t *\n\t * @returns Promise that resolves when loading is complete\n\t *\n\t * @example\n\t * ```typescript\n\t * await manager.loadFromPersistence();\n\t * console.log(`Loaded ${manager.getHistoryLength()} thoughts`);\n\t * ```\n\t */\n\tpublic async loadFromPersistence(): Promise<void> {\n\t\tif (!this._persistenceEnabled || !this._persistence) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\t// Check backend health\n\t\t\tconst isHealthy = await this._persistence.healthy();\n\t\t\tif (!isHealthy) {\n\t\t\t\tthis.log('Persistence backend not healthy, skipping load');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst globalSession = this._getSession();\n\n\t\t\t// Load history\n\t\t\tconst history = await this._persistence.loadHistory();\n\t\t\tif (history.length > 0) {\n\t\t\t\tglobalSession.thought_history = history.slice(-this._maxHistorySize);\n\t\t\t\tthis.log(`Loaded ${globalSession.thought_history.length} thoughts from persistence`);\n\t\t\t}\n\n\t\t\t// Load branches\n\t\t\tconst branchIds = await this._persistence.listBranches();\n\t\t\tfor (const branchId of branchIds) {\n\t\t\t\tconst branchData = await this._persistence.loadBranch(branchId);\n\t\t\t\tif (branchData) {\n\t\t\t\t\tglobalSession.branches[branchId] = branchData.slice(-this._maxBranchSize);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.log(`Loaded ${Object.keys(globalSession.branches).length} branches from persistence`);\n\t\t} catch (error) {\n\t\t\tthis.log('Failed to load from persistence', {\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Checks if persistence is enabled.\n\t *\n\t * @returns true if persistence is enabled, false otherwise\n\t *\n\t * @example\n\t * ```typescript\n\t * if (manager.isPersistenceEnabled()) {\n\t * console.log('Persistence is active');\n\t * }\n\t * ```\n\t */\n\tpublic isPersistenceEnabled(): boolean {\n\t\treturn this._persistenceEnabled;\n\t}\n\n\t/**\n\t * Gets the persistence backend instance.\n\t *\n\t * @returns The persistence backend, or null if not configured\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = manager.getPersistenceBackend();\n\t * if (backend) {\n\t * await backend.healthy();\n\t * }\n\t * ```\n\t */\n\tpublic getPersistenceBackend(): PersistenceBackend | null {\n\t\treturn this._persistence;\n\t}\n\n\t/**\n\t * Sets the event emitter for persistence error events.\n\t * This allows wiring up the event emitter after construction\n\t * (e.g., when the server instance is the emitter).\n\t *\n\t * @param emitter - The event emitter to use for persistence error events\n\t */\n\tpublic setEventEmitter(emitter: PersistenceEventEmitter): void {\n\t\tthis._eventEmitter = emitter;\n\t}\n\n\t/**\n\t * Gracefully shuts down the write buffer and session cleanup.\n\t * Stops the periodic flush timer and session cleanup timer,\n\t * then flushes any remaining buffered writes.\n\t * Should be called during server shutdown before closing the persistence backend.\n\t */\n\tpublic async shutdown(): Promise<void> {\n\t\tthis._stopFlushTimer();\n\t\tthis._stopSessionCleanupTimer();\n\t\tawait this._flushBuffer();\n\t}\n\n\t/**\n\t * Starts the periodic flush timer for the write buffer.\n\t * @private\n\t */\n\tprivate _startFlushTimer(): void {\n\t\tif (this._flushTimer !== null) {\n\t\t\treturn;\n\t\t}\n\t\tthis._flushTimer = setInterval(() => {\n\t\t\tvoid this._flushBuffer();\n\t\t}, this._persistenceFlushInterval);\n\t\t// Allow the process to exit even if the timer is still running\n\t\tif (this._flushTimer && typeof this._flushTimer === 'object' && 'unref' in this._flushTimer) {\n\t\t\tthis._flushTimer.unref();\n\t\t}\n\t}\n\n\t/**\n\t * Stops the periodic flush timer.\n\t * @private\n\t */\n\tprivate _stopFlushTimer(): void {\n\t\tif (this._flushTimer !== null) {\n\t\t\tclearInterval(this._flushTimer);\n\t\t\tthis._flushTimer = null;\n\t\t}\n\t}\n\n\t/**\n\t * Starts the periodic session cleanup timer.\n\t * Runs every 5 minutes to evict sessions that exceeded TTL.\n\t * @private\n\t */\n\tprivate _startSessionCleanupTimer(): void {\n\t\tif (this._sessionCleanupTimer !== null) return;\n\t\tthis._sessionCleanupTimer = setInterval(\n\t\t\t() => {\n\t\t\t\tthis._cleanupStaleSessions();\n\t\t\t},\n\t\t\t5 * 60 * 1000\n\t\t);\n\t\tif (\n\t\t\tthis._sessionCleanupTimer &&\n\t\t\ttypeof this._sessionCleanupTimer === 'object' &&\n\t\t\t'unref' in this._sessionCleanupTimer\n\t\t) {\n\t\t\tthis._sessionCleanupTimer.unref();\n\t\t}\n\t}\n\n\t/**\n\t * Stops the periodic session cleanup timer.\n\t * @private\n\t */\n\tprivate _stopSessionCleanupTimer(): void {\n\t\tif (this._sessionCleanupTimer !== null) {\n\t\t\tclearInterval(this._sessionCleanupTimer);\n\t\t\tthis._sessionCleanupTimer = null;\n\t\t}\n\t}\n\n\t/**\n\t * Evicts sessions that have been inactive longer than SESSION_TTL_MS.\n\t * The global session is never evicted.\n\t * @private\n\t */\n\tprivate _cleanupStaleSessions(): void {\n\t\tconst now = Date.now();\n\t\tfor (const [key, session] of this._sessions) {\n\t\t\t// Never evict the global session\n\t\t\tif (key === HistoryManager.DEFAULT_SESSION) continue;\n\t\t\tif (now - session.lastAccessedAt > HistoryManager.SESSION_TTL_MS) {\n\t\t\t\tthis._sessions.delete(key);\n\t\t\t\tthis.log('Evicted stale session', { sessionId: key });\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Evicts oldest sessions when MAX_SESSIONS is exceeded (LRU).\n\t * The global session is never evicted.\n\t * @private\n\t */\n\tprivate _evictExcessSessions(): void {\n\t\twhile (this._sessions.size > HistoryManager.MAX_SESSIONS) {\n\t\t\tlet oldestKey: string | null = null;\n\t\t\tlet oldestTime = Infinity;\n\t\t\tfor (const [key, session] of this._sessions) {\n\t\t\t\tif (key === HistoryManager.DEFAULT_SESSION) continue;\n\t\t\t\tif (session.lastAccessedAt < oldestTime) {\n\t\t\t\t\toldestTime = session.lastAccessedAt;\n\t\t\t\t\toldestKey = key;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (oldestKey !== null) {\n\t\t\t\tthis._sessions.delete(oldestKey);\n\t\t\t\tthis.log('Evicted oldest session (LRU)', { sessionId: oldestKey });\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Flushes the write buffer to the persistence backend.\n\t *\n\t * Collects all buffered thoughts across all sessions and saves them\n\t * individually with retry logic. On persistent failure (all retries exhausted),\n\t * emits a `persistenceError` event and re-queues failed items.\n\t *\n\t * This method is safe to call concurrently — duplicate calls are skipped.\n\t * @internal\n\t */\n\tpublic async _flushBuffer(): Promise<void> {\n\t\tif (this._isFlushing || !this._persistence) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Collect all pending writes from all sessions\n\t\tconst allPending: ThoughtData[] = [];\n\t\tfor (const session of this._sessions.values()) {\n\t\t\tif (session.writeBuffer.length > 0) {\n\t\t\t\tallPending.push(...session.writeBuffer.splice(0));\n\t\t\t}\n\t\t}\n\n\t\tif (allPending.length === 0) return;\n\n\t\tthis._isFlushing = true;\n\t\tconst failedItems: ThoughtData[] = [];\n\n\t\ttry {\n\t\t\tfor (const thought of allPending) {\n\t\t\t\tconst saved = await this._flushSingleThought(thought);\n\t\t\t\tif (!saved) {\n\t\t\t\t\tfailedItems.push(thought);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._handleFlushResult(failedItems, allPending.length);\n\t\t} finally {\n\t\t\tthis._isFlushing = false;\n\t\t}\n\t}\n\n\t/**\n\t * Flushes a single thought to persistence with retry logic.\n\t * @param thought - The thought to flush\n\t * @returns true if saved successfully, false otherwise\n\t * @private\n\t */\n\tprivate async _flushSingleThought(thought: ThoughtData): Promise<boolean> {\n\t\tconst backoffDelays = [100, 500, 2000];\n\n\t\tfor (let attempt = 0; attempt <= this._persistenceMaxRetries; attempt++) {\n\t\t\ttry {\n\t\t\t\tawait this._persistence!.saveThought(thought);\n\t\t\t\treturn true;\n\t\t\t} catch (err) {\n\t\t\t\tif (attempt < this._persistenceMaxRetries) {\n\t\t\t\t\tconst delay = backoffDelays[attempt] ?? backoffDelays[backoffDelays.length - 1]!;\n\t\t\t\t\tthis.log(`Persistence retry ${attempt + 1}/${this._persistenceMaxRetries}`, {\n\t\t\t\t\t\tthoughtNumber: thought.thought_number,\n\t\t\t\t\t\tdelay,\n\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t});\n\t\t\t\t\tawait this._delay(delay);\n\t\t\t\t} else {\n\t\t\t\t\tthis.log('All persistence retries exhausted for thought', {\n\t\t\t\t\t\tthoughtNumber: thought.thought_number,\n\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Handles the result of a flush operation, re-queuing failures.\n\t * @param failedItems - Thoughts that failed to persist\n\t * @param totalCount - Total number of thoughts attempted\n\t * @private\n\t */\n\tprivate _handleFlushResult(failedItems: ThoughtData[], totalCount: number): void {\n\t\tif (failedItems.length > 0) {\n\t\t\t// Put failed items back in the global session's buffer\n\t\t\tconst globalSession = this._getSession();\n\t\t\tglobalSession.writeBuffer.unshift(...failedItems);\n\t\t\tthis._flushRetryCount++;\n\n\t\t\tconst error = new Error(\n\t\t\t\t`Failed to persist ${failedItems.length} thoughts after ${this._persistenceMaxRetries} retries`\n\t\t\t);\n\t\t\tthis._eventEmitter?.emit('persistenceError', {\n\t\t\t\toperation: 'flushBuffer',\n\t\t\t\terror,\n\t\t\t});\n\n\t\t\tthis.log('Flush completed with failures', {\n\t\t\t\tfailed: failedItems.length,\n\t\t\t\ttotal: totalCount,\n\t\t\t\tconsecutiveFailures: this._flushRetryCount,\n\t\t\t});\n\t\t} else {\n\t\t\t// Reset retry count on full success\n\t\t\tthis._flushRetryCount = 0;\n\t\t}\n\t}\n\n\t/**\n\t * Returns a promise that resolves after the specified delay.\n\t * @param ms - Delay in milliseconds\n\t * @private\n\t */\n\tprivate _delay(ms: number): Promise<void> {\n\t\treturn new Promise((resolve) => setTimeout(resolve, ms));\n\t}\n\n\t/**\n\t * Gets the current write buffer length across all sessions.\n\t * Useful for monitoring and testing.\n\t */\n\tpublic getWriteBufferLength(): number {\n\t\tlet total = 0;\n\t\tfor (const session of this._sessions.values()) {\n\t\t\ttotal += session.writeBuffer.length;\n\t\t}\n\t\treturn total;\n\t}\n}\n"],"names":["ABSOLUTE_MAX_HISTORY_SIZE","HistoryManager","Map","config","NullLogger","requestedMaxSize","Math","message","meta","sessionId","key","session","undefined","Date","thought","branchId","Object","err","Error","String","branchCount","branchesToRemove","removed","Array","isHealthy","globalSession","history","branchIds","branchData","error","emitter","setInterval","clearInterval","now","oldestKey","oldestTime","Infinity","allPending","failedItems","saved","backoffDelays","attempt","delay","totalCount","ms","Promise","resolve","setTimeout","total"],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for history and branch management.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the `IHistoryManager` interface which defines the contract
|
|
5
|
+
* for history manager implementations. This allows for decoupling and testability.
|
|
6
|
+
*
|
|
7
|
+
* @module IHistoryManager
|
|
8
|
+
*/
|
|
9
|
+
import type { ThoughtData } from './thought.js';
|
|
10
|
+
/**
|
|
11
|
+
* Interface for history and branch management.
|
|
12
|
+
*
|
|
13
|
+
* This interface defines the contract for history manager implementations,
|
|
14
|
+
* allowing for decoupling between components like ThoughtProcessor and
|
|
15
|
+
* concrete implementations. It supports dependency injection and mocking
|
|
16
|
+
* for testing purposes.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Using the interface for dependency injection
|
|
21
|
+
* class MyComponent {
|
|
22
|
+
* constructor(private history: IHistoryManager) {}
|
|
23
|
+
*
|
|
24
|
+
* addThought(thought: ThoughtData) {
|
|
25
|
+
* this.history.addThought(thought);
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* // Mock implementation for testing
|
|
30
|
+
* class MockHistoryManager implements IHistoryManager {
|
|
31
|
+
* private _history: ThoughtData[] = [];
|
|
32
|
+
* addThought(thought: ThoughtData): void { this._history.push(thought); }
|
|
33
|
+
* getHistory(): ThoughtData[] { return this._history; }
|
|
34
|
+
* getHistoryLength(): number { return this._history.length; }
|
|
35
|
+
* getBranches(): Record<string, ThoughtData[]> { return {}; }
|
|
36
|
+
* getBranchIds(): string[] { return []; }
|
|
37
|
+
* clear(): void { this._history = []; }
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export interface IHistoryManager {
|
|
42
|
+
/**
|
|
43
|
+
* Adds a thought to the history.
|
|
44
|
+
* Session is determined by `thought.session_id` (defaults to global session).
|
|
45
|
+
*
|
|
46
|
+
* @param thought - The thought data to add
|
|
47
|
+
*/
|
|
48
|
+
addThought(thought: ThoughtData): void;
|
|
49
|
+
/**
|
|
50
|
+
* Gets the complete thought history.
|
|
51
|
+
*
|
|
52
|
+
* @param sessionId - Optional session ID for session-scoped results
|
|
53
|
+
* @returns An array of all thoughts in chronological order
|
|
54
|
+
*/
|
|
55
|
+
getHistory(sessionId?: string): ThoughtData[];
|
|
56
|
+
/**
|
|
57
|
+
* Gets the current length of the thought history.
|
|
58
|
+
*
|
|
59
|
+
* @param sessionId - Optional session ID for session-scoped results
|
|
60
|
+
* @returns The number of thoughts in history
|
|
61
|
+
*/
|
|
62
|
+
getHistoryLength(sessionId?: string): number;
|
|
63
|
+
/**
|
|
64
|
+
* Gets all branches.
|
|
65
|
+
*
|
|
66
|
+
* @param sessionId - Optional session ID for session-scoped results
|
|
67
|
+
* @returns A record mapping branch IDs to their thought arrays
|
|
68
|
+
*/
|
|
69
|
+
getBranches(sessionId?: string): Record<string, ThoughtData[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Gets all branch IDs.
|
|
72
|
+
*
|
|
73
|
+
* @param sessionId - Optional session ID for session-scoped results
|
|
74
|
+
* @returns An array of branch identifiers
|
|
75
|
+
*/
|
|
76
|
+
getBranchIds(sessionId?: string): string[];
|
|
77
|
+
/**
|
|
78
|
+
* Clears history and branches.
|
|
79
|
+
* If sessionId is provided, clears only that session.
|
|
80
|
+
* If omitted, clears all sessions.
|
|
81
|
+
*
|
|
82
|
+
* @param sessionId - Optional session ID to clear
|
|
83
|
+
*/
|
|
84
|
+
clear(sessionId?: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* Gets the most recently available MCP tools from the session.
|
|
87
|
+
*
|
|
88
|
+
* @param sessionId - Optional session ID for session-scoped results
|
|
89
|
+
* @returns The last-seen array of MCP tool names, or undefined if never set
|
|
90
|
+
*/
|
|
91
|
+
getAvailableMcpTools(sessionId?: string): string[] | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Gets the most recently available skills from the session.
|
|
94
|
+
*
|
|
95
|
+
* @param sessionId - Optional session ID for session-scoped results
|
|
96
|
+
* @returns The last-seen array of skill names, or undefined if never set
|
|
97
|
+
*/
|
|
98
|
+
getAvailableSkills(sessionId?: string): string[] | undefined;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=IHistoryManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IHistoryManager.d.ts","sourceRoot":"","sources":["../../src/core/IHistoryManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;;OAKG;IACH,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAEvC;;;;;OAKG;IACH,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAAC;IAE9C;;;;;OAKG;IACH,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAE7C;;;;;OAKG;IACH,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IAE/D;;;;;OAKG;IACH,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE3C;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC;;;;;OAKG;IACH,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;IAE/D;;;;;OAKG;IACH,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;CAC7D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|