@stackmemoryai/stackmemory
Version:
Lossless, project-scoped memory for AI coding tools. Durable context across sessions with 56 MCP tools, FTS5 search, conductor orchestrator, loop/watch monitoring, snapshot capture, pre-flight overlap checks, Claude/Codex/OpenCode wrappers, Linear sync, a
496 lines (487 loc) • 15.7 kB
JavaScript
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { v4 as uuidv4 } from "uuid";
import * as fs from "fs/promises";
import * as path from "path";
import { logger } from "../../../core/monitoring/logger.js";
import { RalphStackMemoryBridge } from "../bridge/ralph-stackmemory-bridge.js";
class ExtendedCoherenceManager {
activeSessions = /* @__PURE__ */ new Map();
baseDir;
monitoringInterval;
performanceHistory = /* @__PURE__ */ new Map();
constructor(baseDir = "./.coherence-sessions") {
this.baseDir = baseDir;
}
/**
* Initialize the coherence management system
*/
async initialize() {
await fs.mkdir(this.baseDir, { recursive: true });
this.monitoringInterval = setInterval(
() => this.monitorActiveSessionsHealth(),
6e4
// Check every minute
);
logger.info("Extended Coherence Manager initialized", {
baseDir: this.baseDir,
monitoringEnabled: true
});
}
/**
* Start an extended coherence work session
*/
async startCoherenceSession(agentConfig, taskConfig, sessionConfig) {
const sessionId = uuidv4();
const defaultConfig = this.generateConfigForComplexity(
taskConfig.complexity
);
const config = { ...defaultConfig, ...sessionConfig };
const session = {
id: sessionId,
agent: agentConfig,
task: {
...taskConfig,
breakpoints: taskConfig.breakpoints || this.generateBreakpoints(taskConfig)
},
config,
state: {
status: "active",
currentPhase: "initialization",
completedMilestones: [],
lastCheckpoint: Date.now(),
interventionCount: 0,
refreshCount: 0
},
metrics: [],
interventions: []
};
this.activeSessions.set(sessionId, session);
await this.initializeSessionWorkspace(session);
await this.launchAgentSession(session);
logger.info("Extended coherence session started", {
sessionId,
agent: agentConfig.role,
estimatedDuration: taskConfig.estimatedDuration,
maxDuration: config.maxDuration
});
return sessionId;
}
/**
* Generate configuration optimized for task complexity
*/
generateConfigForComplexity(complexity) {
const configs = {
low: {
maxDuration: 60,
// 1 hour
coherenceThreshold: 0.7,
checkpointInterval: 15,
// 15 minutes
refreshStrategy: "checkpoint",
enableMemoryPalace: false,
enableProgressTracking: true,
enableAutoRefresh: false,
enableHealthMonitoring: true
},
medium: {
maxDuration: 180,
// 3 hours
coherenceThreshold: 0.8,
checkpointInterval: 10,
// 10 minutes
refreshStrategy: "context_refresh",
enableMemoryPalace: true,
enableProgressTracking: true,
enableAutoRefresh: true,
enableHealthMonitoring: true
},
high: {
maxDuration: 360,
// 6 hours
coherenceThreshold: 0.85,
checkpointInterval: 8,
// 8 minutes
refreshStrategy: "context_refresh",
enableMemoryPalace: true,
enableProgressTracking: true,
enableAutoRefresh: true,
enableHealthMonitoring: true
},
very_high: {
maxDuration: 720,
// 12 hours
coherenceThreshold: 0.9,
checkpointInterval: 5,
// 5 minutes
refreshStrategy: "full_restart",
enableMemoryPalace: true,
enableProgressTracking: true,
enableAutoRefresh: true,
enableHealthMonitoring: true
}
};
return configs[complexity];
}
/**
* Monitor active sessions for coherence degradation
*/
async monitorActiveSessionsHealth() {
for (const [_sessionId, session] of this.activeSessions) {
if (session.state.status === "active") {
await this.assessSessionCoherence(session);
}
}
}
/**
* Assess session coherence and intervene if necessary
*/
async assessSessionCoherence(session) {
const metrics = await this.calculateCoherenceMetrics(session);
session.metrics.push(metrics);
if (session.metrics.length > 10) {
session.metrics.shift();
}
const overallCoherence = this.calculateOverallCoherence(metrics);
logger.debug("Session coherence assessment", {
sessionId: session.id,
coherence: overallCoherence,
threshold: session.config.coherenceThreshold,
duration: metrics.duration
});
if (overallCoherence < session.config.coherenceThreshold) {
await this.interventeInSession(
session,
"coherence_degradation",
overallCoherence
);
}
const timeSinceCheckpoint = Date.now() - session.state.lastCheckpoint;
const checkpointDue = timeSinceCheckpoint > session.config.checkpointInterval * 60 * 1e3;
if (checkpointDue) {
await this.checkpointSession(session);
}
}
/**
* Calculate comprehensive coherence metrics
*/
async calculateCoherenceMetrics(session) {
const now = Date.now();
const duration = (now - session.metrics[0]?.startTime || now) / (1e3 * 60);
const recentOutputs = await this.getRecentAgentOutputs(session);
const outputQuality = this.assessOutputQuality(recentOutputs);
const contextRetention = this.assessContextRetention(
recentOutputs,
session.task
);
const taskRelevance = this.assessTaskRelevance(recentOutputs, session.task);
const repetitionRate = this.calculateRepetitionRate(recentOutputs);
const divergenceRate = this.calculateDivergenceRate(
recentOutputs,
session.task
);
const errorRate = this.calculateErrorRate(recentOutputs);
const progressRate = this.calculateProgressRate(session);
return {
sessionId: session.id,
startTime: session.metrics[0]?.startTime || now,
currentTime: now,
duration,
outputQuality,
contextRetention,
taskRelevance,
progressRate,
repetitionRate,
divergenceRate,
errorRate,
memoryUsage: await this.getMemoryUsage(session),
contextWindowUsage: await this.getContextWindowUsage(session),
stateCheckpoints: session.interventions.filter(
(i) => i.type === "checkpoint"
).length
};
}
/**
* Calculate overall coherence score
*/
calculateOverallCoherence(metrics) {
const weights = {
outputQuality: 0.3,
contextRetention: 0.25,
taskRelevance: 0.25,
repetitionPenalty: 0.1,
// penalty for repetition
divergencePenalty: 0.1
// penalty for divergence
};
const baseScore = metrics.outputQuality * weights.outputQuality + metrics.contextRetention * weights.contextRetention + metrics.taskRelevance * weights.taskRelevance;
const penalties = metrics.repetitionRate * weights.repetitionPenalty + metrics.divergenceRate * weights.divergencePenalty;
return Math.max(0, baseScore - penalties);
}
/**
* Intervene in a session to restore coherence
*/
async interventeInSession(session, reason, currentCoherence) {
logger.warn("Intervening in session due to coherence degradation", {
sessionId: session.id,
reason,
currentCoherence,
interventionCount: session.state.interventionCount
});
const intervention = {
timestamp: Date.now(),
type: session.config.refreshStrategy,
reason,
effectiveness: 0
// will be calculated later
};
switch (session.config.refreshStrategy) {
case "checkpoint":
await this.checkpointSession(session);
break;
case "context_refresh":
await this.refreshSessionContext(session);
break;
case "full_restart":
await this.restartSession(session);
break;
default:
await this.provideGuidance(session, reason);
intervention.type = "guidance";
}
session.interventions.push(intervention);
session.state.interventionCount++;
const _previousStatus = session.state.status;
session.state.status = "degraded";
setTimeout(async () => {
const newMetrics = await this.calculateCoherenceMetrics(session);
const newCoherence = this.calculateOverallCoherence(newMetrics);
intervention.effectiveness = Math.max(0, newCoherence - currentCoherence);
if (newCoherence > session.config.coherenceThreshold) {
session.state.status = "active";
logger.info("Session coherence restored", {
sessionId: session.id,
newCoherence,
effectiveness: intervention.effectiveness
});
}
}, 12e4);
}
/**
* Create a checkpoint of session state
*/
async checkpointSession(session) {
const checkpointPath = path.join(
this.baseDir,
session.id,
`checkpoint-${Date.now()}.json`
);
const checkpointData = {
timestamp: Date.now(),
state: session.state,
recentMetrics: session.metrics.slice(-3),
currentPhase: session.state.currentPhase,
completedMilestones: session.state.completedMilestones,
// Include recent agent context
contextSummary: await this.generateContextSummary(session)
};
await fs.writeFile(checkpointPath, JSON.stringify(checkpointData, null, 2));
session.state.lastCheckpoint = Date.now();
logger.info("Session checkpoint created", {
sessionId: session.id,
checkpointPath
});
}
/**
* Refresh session context to restore coherence
*/
async refreshSessionContext(session) {
logger.info("Refreshing session context", { sessionId: session.id });
const refreshPrompt = await this.generateContextRefreshPrompt(session);
await this.applyContextRefresh(session, refreshPrompt);
session.state.refreshCount++;
}
/**
* Restart session from last good checkpoint
*/
async restartSession(session) {
logger.info("Restarting session from checkpoint", {
sessionId: session.id
});
const checkpoint = await this.loadLatestCheckpoint(session);
if (checkpoint) {
session.state = { ...checkpoint.state };
await this.restartAgentFromCheckpoint(session, checkpoint);
} else {
await this.restartAgentFromBeginning(session);
}
}
/**
* Initialize workspace for a coherence session
*/
async initializeSessionWorkspace(session) {
const sessionDir = path.join(this.baseDir, session.id);
await fs.mkdir(sessionDir, { recursive: true });
const manifest = {
sessionId: session.id,
agent: session.agent,
task: session.task,
config: session.config,
createdAt: Date.now()
};
await fs.writeFile(
path.join(sessionDir, "manifest.json"),
JSON.stringify(manifest, null, 2)
);
}
/**
* Launch the actual agent work session
*/
async launchAgentSession(session) {
const sessionDir = path.join(this.baseDir, session.id);
const ralph = new RalphStackMemoryBridge({
baseDir: sessionDir,
maxIterations: Math.ceil(session.config.maxDuration / 5),
// ~5 min per iteration
useStackMemory: true
});
await ralph.initialize({
task: this.buildExtendedCoherencePrompt(session),
criteria: session.task.breakpoints.join("\n")
});
ralph.run().catch((error) => {
logger.error("Extended coherence session failed", {
sessionId: session.id,
error: error.message
});
session.state.status = "failed";
});
}
/**
* Build prompt optimized for extended coherence
*/
buildExtendedCoherencePrompt(session) {
return `
# EXTENDED COHERENCE WORK SESSION
## Your Mission
${session.task.description}
## Session Parameters
- Estimated Duration: ${session.task.estimatedDuration} minutes
- Maximum Duration: ${session.config.maxDuration} minutes
- Coherence Threshold: ${session.config.coherenceThreshold * 100}%
## Coherence Guidelines
1. **Maintain Focus**: Stay on task throughout the entire session
2. **Track Progress**: Document incremental progress at each step
3. **Context Awareness**: Reference previous work and maintain consistency
4. **Quality Control**: Regularly assess your output quality
5. **Milestone Reporting**: Report when you reach natural breakpoints
## Breakpoints & Milestones
${session.task.breakpoints.map((bp, i) => `${i + 1}. ${bp}`).join("\n")}
## Extended Session Strategy
- Take regular checkpoint breaks (every ${session.config.checkpointInterval} minutes)
- Summarize your progress regularly
- Ask for context refresh if you feel you're losing focus
- Maintain awareness of the overall project goal
- Break complex tasks into smaller, manageable chunks
## Memory Palace (if enabled)
${session.config.enableMemoryPalace ? `
Use structured memory organization:
- **Project Context**: Overall goals and requirements
- **Current Status**: What's been completed and what's next
- **Working Memory**: Current task details and immediate context
- **Reference Memory**: Important patterns, decisions, and learnings
` : ""}
## Success Criteria
- Complete the task within the allocated time
- Maintain high output quality throughout
- Document progress and decisions clearly
- Stay coherent and focused for the entire session
Begin your extended coherence work session now.
`;
}
// Placeholder implementations for helper methods
async getRecentAgentOutputs(_session) {
return [];
}
assessOutputQuality(_outputs) {
return 0.8;
}
assessContextRetention(_outputs, _task) {
return 0.7;
}
assessTaskRelevance(_outputs, _task) {
return 0.9;
}
calculateRepetitionRate(_outputs) {
return 0.1;
}
calculateDivergenceRate(_outputs, _task) {
return 0.05;
}
calculateErrorRate(_outputs) {
return 0.02;
}
calculateProgressRate(_session) {
return 2.5;
}
async getMemoryUsage(_session) {
return 150;
}
async getContextWindowUsage(_session) {
return 65;
}
generateBreakpoints(_taskConfig) {
return [
"Initial analysis complete",
"Core implementation finished",
"Testing phase complete",
"Final review and cleanup done"
];
}
async generateContextSummary(session) {
return `Session ${session.id} context summary`;
}
async generateContextRefreshPrompt(_session) {
return "Context refresh prompt";
}
async applyContextRefresh(_session, _prompt) {
}
async loadLatestCheckpoint(_session) {
return null;
}
async restartAgentFromCheckpoint(_session, _checkpoint) {
}
async restartAgentFromBeginning(_session) {
}
async provideGuidance(_session, _reason) {
}
/**
* Get extended coherence capabilities
*/
getCoherenceCapabilities() {
const activeSessions = Array.from(this.activeSessions.values());
return {
maxSessionDuration: Math.max(
...activeSessions.map((s) => s.config.maxDuration)
),
activeSessionCount: activeSessions.filter(
(s) => s.state.status === "active"
).length,
averageCoherence: activeSessions.reduce((sum, s) => {
const recent = s.metrics.slice(-1)[0];
return sum + (recent ? this.calculateOverallCoherence(recent) : 0);
}, 0) / activeSessions.length,
totalInterventions: activeSessions.reduce(
(sum, s) => sum + s.interventions.length,
0
)
};
}
}
var extended_coherence_sessions_default = ExtendedCoherenceManager;
export {
ExtendedCoherenceManager,
extended_coherence_sessions_default as default
};