/**
* Recovery Engine
*
* Implements memory recovery capabilities using multiple strategies including
* associative recovery, schema-based reconstruction, and partial cue recovery.
* Tracks recovery success and continuously improves recovery effectiveness.
*/
import {
AssociativeRecoveryStrategy,
EnhancedRecoveryResult,
FailurePattern,
IRecoveryEngine,
PartialCueRecoveryStrategy,
QualityIssue,
RecoveryAttempt,
RecoveryConfidenceAssessment,
RecoveryCue,
RecoveryMetadata,
RecoveryQualityAssessment,
RecoveryResult,
RecoveryStatistics,
RecoveryStrategy,
RecoveryTrend,
RecoveryValidation,
ReliabilityFactor,
SchemaBasedRecoveryStrategy,
UncertaintySource,
} from "../../interfaces/forgetting.js";
import { Concept, Episode } from "../../types/core.js";
export interface RecoveryEngineConfig {
max_recovery_attempts: number;
confidence_threshold: number;
enable_strategy_learning: boolean;
enable_quality_assessment: boolean;
recovery_timeout_ms: number;
statistics_retention_days: number;
}
export class RecoveryEngine implements IRecoveryEngine {
private config: RecoveryEngineConfig;
private recoveryStrategies: Map<string, RecoveryStrategy> = new Map();
private recoveryHistory: Map<string, RecoveryAttempt[]> = new Map();
private recoveryStatistics: RecoveryStatistics;
private validationHistory: Map<string, RecoveryValidation[]> = new Map();
constructor(config?: Partial<RecoveryEngineConfig>) {
this.config = {
max_recovery_attempts: 5,
confidence_threshold: 0.3,
enable_strategy_learning: true,
enable_quality_assessment: true,
recovery_timeout_ms: 30000,
statistics_retention_days: 90,
...config,
};
this.recoveryStatistics = this.initializeStatistics();
this.initializeDefaultStrategies();
}
private initializeStatistics(): RecoveryStatistics {
return {
total_recovery_attempts: 0,
successful_recoveries: 0,
partial_recoveries: 0,
failed_recoveries: 0,
average_recovery_confidence: 0,
average_recovery_time_ms: 0,
strategy_success_rates: new Map(),
improvement_trends: [],
common_failure_patterns: [],
};
}
private initializeDefaultStrategies(): void {
// Add associative recovery strategy
this.addRecoveryStrategy(
new AssociativeRecoveryStrategyImpl({
name: "associative_recovery",
description:
"Recover memories using associative networks and spreading activation",
confidence_threshold: 0.4,
association_weight: 0.7,
spreading_activation_depth: 3,
similarity_threshold: 0.6,
})
);
// Add schema-based recovery strategy
this.addRecoveryStrategy(
new SchemaBasedRecoveryStrategyImpl({
name: "schema_based_recovery",
description:
"Recover memories using schema matching and pattern completion",
confidence_threshold: 0.5,
schema_matching_threshold: 0.7,
pattern_completion_enabled: true,
contextual_inference_weight: 0.8,
})
);
// Add partial cue recovery strategy
this.addRecoveryStrategy(
new PartialCueRecoveryStrategyImpl({
name: "partial_cue_recovery",
description: "Recover memories using partial cues and reconstruction",
confidence_threshold: 0.3,
minimum_cue_strength: 0.4,
cue_combination_method: "weighted_sum",
temporal_decay_compensation: true,
})
);
}
async attemptRecovery(
memory_id: string,
recovery_cues: RecoveryCue[],
recovery_metadata?: RecoveryMetadata
): Promise<EnhancedRecoveryResult> {
const startTime = Date.now();
const attempts: RecoveryAttempt[] = [];
let bestAttempt: RecoveryAttempt | null = null;
let bestConfidence = 0;
// Validate inputs
if (!recovery_cues || recovery_cues.length === 0) {
throw new Error("Recovery cues are required for memory recovery");
}
if (!recovery_metadata) {
console.warn(
`No recovery metadata provided for memory ${memory_id}, using cues only`
);
}
// Sort strategies by their assessed recovery probability
const strategiesWithProbability = await Promise.all(
Array.from(this.recoveryStrategies.values()).map(async (strategy) => ({
strategy,
probability: recovery_metadata
? await strategy.assessRecoveryProbability(
recovery_cues,
recovery_metadata
)
: 0.5, // Default probability when no metadata
}))
);
strategiesWithProbability.sort((a, b) => b.probability - a.probability);
// Attempt recovery with each strategy
for (const { strategy } of strategiesWithProbability) {
if (attempts.length >= this.config.max_recovery_attempts) {
break;
}
try {
const attempt = recovery_metadata
? await strategy.recover(memory_id, recovery_cues, recovery_metadata)
: await this.recoverWithoutMetadata(
strategy,
memory_id,
recovery_cues
);
attempts.push(attempt);
// Track the best attempt
if (attempt.success && attempt.confidence > bestConfidence) {
bestAttempt = attempt;
bestConfidence = attempt.confidence;
}
// If we have a high-confidence recovery, we can stop
if (attempt.confidence > 0.9) {
break;
}
} catch (error) {
console.error(`Recovery strategy ${strategy.name} failed:`, error);
attempts.push({
strategy_name: strategy.name,
success: false,
confidence: 0,
partial_recovery: false,
recovered_elements: [],
missing_elements: ["all"],
recovery_method_details: `Strategy failed: ${error}`,
processing_time_ms: Date.now() - startTime,
});
}
}
// Determine overall recovery result
const success = bestAttempt?.success ?? false;
const recoveredMemory = bestAttempt?.recovered_content;
const combinedConfidence = this.calculateCombinedConfidence(attempts);
const partialRecovery = attempts.some((a) => a.partial_recovery);
// Assess recovery quality if enabled
const qualityAssessment =
this.config.enable_quality_assessment && recoveredMemory
? await this.assessRecoveryQuality(
recoveredMemory,
recovery_metadata,
recovery_cues
)
: this.createDefaultQualityAssessment();
// Create enhanced recovery result
const result: EnhancedRecoveryResult = {
success,
recovered_memory: recoveredMemory as Episode | Concept | undefined,
recovery_confidence: combinedConfidence,
recovery_method: bestAttempt?.strategy_name ?? "none",
partial_recovery: partialRecovery,
missing_elements: bestAttempt?.missing_elements ?? [],
recovery_metadata_used:
recovery_metadata ?? this.createEmptyRecoveryMetadata(memory_id),
recovery_attempts: attempts,
best_attempt: bestAttempt ?? attempts[0],
combined_confidence: combinedConfidence,
recovery_strategies_used: attempts.map((a) => a.strategy_name),
recovery_time_ms: Date.now() - startTime,
quality_assessment: qualityAssessment,
};
// Update statistics
await this.updateRecoveryStatistics(result);
// Store recovery history
this.recoveryHistory.set(memory_id, attempts);
return result;
}
async assessRecoveryConfidence(
recovered_content: any,
original_metadata: RecoveryMetadata
): Promise<RecoveryConfidenceAssessment> {
const reliabilityFactors: ReliabilityFactor[] = [];
const uncertaintySources: UncertaintySource[] = [];
const validationSuggestions: string[] = [];
// Assess content accuracy based on available metadata
let contentAccuracy = 0.5; // Default moderate confidence
let completeness = 0.5;
if (original_metadata) {
// Check content hash if available
if (original_metadata.original_content_hash) {
const recoveredHash = this.generateContentHash(recovered_content);
const hashMatch =
recoveredHash === original_metadata.original_content_hash;
contentAccuracy = hashMatch ? 0.95 : 0.3;
reliabilityFactors.push({
factor_name: "content_hash_match",
impact: hashMatch ? 0.4 : -0.3,
description: hashMatch
? "Content hash matches original"
: "Content hash differs from original",
evidence: [`Hash comparison: ${hashMatch ? "match" : "mismatch"}`],
});
}
// Assess completeness based on recovery cues
const cuesCovered = original_metadata.recovery_cues.length;
const expectedCues = Math.max(cuesCovered, 3); // Minimum expected cues
completeness = Math.min(cuesCovered / expectedCues, 1);
reliabilityFactors.push({
factor_name: "recovery_cues_coverage",
impact: (completeness - 0.5) * 0.4,
description: `${cuesCovered} recovery cues available`,
evidence: [`Cue coverage: ${(completeness * 100).toFixed(1)}%`],
});
// Check degradation history impact
const totalDegradation = original_metadata.degradation_history.reduce(
(sum, record) => sum + record.degradation_factor,
0
);
if (totalDegradation > 0) {
const degradationImpact = -totalDegradation * 0.3;
reliabilityFactors.push({
factor_name: "degradation_impact",
impact: degradationImpact,
description: `Memory underwent ${(totalDegradation * 100).toFixed(
1
)}% degradation`,
evidence: [
`Degradation stages: ${original_metadata.degradation_history.length}`,
],
});
uncertaintySources.push({
source_name: "memory_degradation",
uncertainty_level: totalDegradation * 0.5,
description: "Memory content may be incomplete due to degradation",
mitigation_strategies: [
"Cross-reference with related memories",
"Validate with external sources",
],
});
}
}
// Add general uncertainty sources
uncertaintySources.push({
source_name: "reconstruction_artifacts",
uncertainty_level: 0.2,
description: "Recovery process may introduce reconstruction artifacts",
mitigation_strategies: [
"Compare with similar memories",
"Verify key facts independently",
],
});
// Generate validation suggestions
validationSuggestions.push(
"Cross-reference recovered content with related memories"
);
validationSuggestions.push("Verify key facts and dates independently");
if (original_metadata?.association_fingerprint) {
validationSuggestions.push("Check consistency with associated memories");
}
// Calculate overall confidence
const baseConfidence = (contentAccuracy + completeness) / 2;
const reliabilityAdjustment = reliabilityFactors.reduce(
(sum, factor) => sum + factor.impact,
0
);
const overallConfidence = Math.max(
0.1,
Math.min(1, baseConfidence + reliabilityAdjustment)
);
return {
overall_confidence: overallConfidence,
content_accuracy_estimate: contentAccuracy,
completeness_estimate: completeness,
reliability_factors: reliabilityFactors,
uncertainty_sources: uncertaintySources,
validation_suggestions: validationSuggestions,
};
}
async trackRecoverySuccess(
memory_id: string,
recovery_result: RecoveryResult,
user_validation?: RecoveryValidation
): Promise<void> {
// Store user validation if provided
if (user_validation) {
const validations = this.validationHistory.get(memory_id) ?? [];
validations.push(user_validation);
this.validationHistory.set(memory_id, validations);
// Update strategy success rates based on validation
if (this.config.enable_strategy_learning) {
await this.updateStrategyLearning(recovery_result, user_validation);
}
}
// Update recovery statistics
this.recoveryStatistics.total_recovery_attempts++;
if (recovery_result.success) {
if (recovery_result.partial_recovery) {
this.recoveryStatistics.partial_recoveries++;
} else {
this.recoveryStatistics.successful_recoveries++;
}
} else {
this.recoveryStatistics.failed_recoveries++;
}
// Update average confidence
const totalAttempts = this.recoveryStatistics.total_recovery_attempts;
const currentAvg = this.recoveryStatistics.average_recovery_confidence;
this.recoveryStatistics.average_recovery_confidence =
(currentAvg * (totalAttempts - 1) + recovery_result.recovery_confidence) /
totalAttempts;
}
async getRecoveryStatistics(): Promise<RecoveryStatistics> {
// Calculate improvement trends
const trends = await this.calculateRecoveryTrends();
// Identify failure patterns
const failurePatterns = await this.identifyFailurePatterns();
return {
...this.recoveryStatistics,
improvement_trends: trends,
common_failure_patterns: failurePatterns,
};
}
addRecoveryStrategy(strategy: RecoveryStrategy): void {
this.recoveryStrategies.set(strategy.name, strategy);
// Initialize success rate tracking
if (!this.recoveryStatistics.strategy_success_rates.has(strategy.name)) {
this.recoveryStatistics.strategy_success_rates.set(strategy.name, 0);
}
}
removeRecoveryStrategy(strategyName: string): void {
this.recoveryStrategies.delete(strategyName);
this.recoveryStatistics.strategy_success_rates.delete(strategyName);
}
// Private helper methods
private async recoverWithoutMetadata(
strategy: RecoveryStrategy,
memory_id: string,
recovery_cues: RecoveryCue[]
): Promise<RecoveryAttempt> {
// Create minimal recovery metadata from cues
const minimalMetadata: RecoveryMetadata =
this.createEmptyRecoveryMetadata(memory_id);
minimalMetadata.recovery_cues = recovery_cues;
return await strategy.recover(memory_id, recovery_cues, minimalMetadata);
}
private createEmptyRecoveryMetadata(memory_id: string): RecoveryMetadata {
return {
original_memory_id: memory_id,
original_content_hash: "",
original_importance: 0.5,
original_timestamp: Date.now(),
degradation_history: [],
recovery_cues: [],
association_fingerprint: {
strong_associations: [],
weak_associations: [],
semantic_clusters: [],
temporal_neighbors: [],
contextual_tags: [],
},
content_summary: "",
recovery_difficulty_estimate: 0.5,
preservation_timestamp: Date.now(),
};
}
private calculateCombinedConfidence(attempts: RecoveryAttempt[]): number {
if (attempts.length === 0) return 0;
const successfulAttempts = attempts.filter((a) => a.success);
if (successfulAttempts.length === 0) return 0;
// Use weighted average of successful attempts
const totalWeight = successfulAttempts.reduce(
(sum, a) => sum + a.confidence,
0
);
return totalWeight / successfulAttempts.length;
}
private async assessRecoveryQuality(
recovered_content: any,
recovery_metadata?: RecoveryMetadata,
_recovery_cues?: RecoveryCue[]
): Promise<RecoveryQualityAssessment> {
const qualityIssues: QualityIssue[] = [];
// Assess content coherence
const contentCoherence = this.assessContentCoherence(recovered_content);
// Assess contextual consistency
const contextualConsistency = recovery_metadata
? this.assessContextualConsistency(recovered_content, recovery_metadata)
: 0.5;
// Assess temporal accuracy
const temporalAccuracy = recovery_metadata
? this.assessTemporalAccuracy(recovered_content, recovery_metadata)
: 0.5;
// Assess associative integrity
const associativeIntegrity = recovery_metadata
? this.assessAssociativeIntegrity(recovered_content, recovery_metadata)
: 0.5;
// Calculate overall quality
const overallQuality =
(contentCoherence +
contextualConsistency +
temporalAccuracy +
associativeIntegrity) /
4;
// Identify quality issues
if (contentCoherence < 0.6) {
qualityIssues.push({
issue_type: "inconsistency",
severity: "medium",
description: "Recovered content shows internal inconsistencies",
affected_content: ["content_structure"],
suggested_resolution: "Review and validate content structure",
});
}
if (contextualConsistency < 0.5) {
qualityIssues.push({
issue_type: "gap",
severity: "medium",
description: "Contextual information may be incomplete",
affected_content: ["context_data"],
suggested_resolution: "Cross-reference with related memories",
});
}
return {
content_coherence: contentCoherence,
contextual_consistency: contextualConsistency,
temporal_accuracy: temporalAccuracy,
associative_integrity: associativeIntegrity,
overall_quality: overallQuality,
quality_issues: qualityIssues,
};
}
private createDefaultQualityAssessment(): RecoveryQualityAssessment {
return {
content_coherence: 0.5,
contextual_consistency: 0.5,
temporal_accuracy: 0.5,
associative_integrity: 0.5,
overall_quality: 0.5,
quality_issues: [],
};
}
private assessContentCoherence(content: any): number {
// Simplified coherence assessment
if (!content) return 0;
if (typeof content === "string") {
// Basic string coherence checks
const hasRepeatedWords = /\b(\w+)\s+\1\b/i.test(content);
const hasBasicStructure = content.length > 10 && content.includes(" ");
return hasBasicStructure && !hasRepeatedWords ? 0.8 : 0.4;
}
return 0.6; // Default for non-string content
}
private assessContextualConsistency(
content: any,
metadata: RecoveryMetadata
): number {
// Check if recovered content is consistent with metadata context
let consistency = 0.5;
// Check against content summary
if (metadata.content_summary && typeof content === "string") {
const summaryWords = metadata.content_summary.toLowerCase().split(" ");
const contentWords = content.toLowerCase().split(" ");
const overlap = summaryWords.filter((word) =>
contentWords.includes(word)
).length;
consistency += (overlap / summaryWords.length) * 0.3;
}
// Check against contextual tags
if (metadata.association_fingerprint.contextual_tags.length > 0) {
// Simplified check - in real implementation, would use more sophisticated matching
consistency += 0.2;
}
return Math.min(consistency, 1);
}
private assessTemporalAccuracy(
_content: any,
metadata: RecoveryMetadata
): number {
// Assess if temporal aspects of recovered content are accurate
const timeDiff = Date.now() - metadata.original_timestamp;
const daysDiff = timeDiff / (1000 * 60 * 60 * 24);
// Older memories are harder to verify temporally
return Math.max(0.3, 1 - (daysDiff / 365) * 0.5);
}
private assessAssociativeIntegrity(
_content: any,
metadata: RecoveryMetadata
): number {
// Assess if associative relationships are maintained
const fingerprint = metadata.association_fingerprint;
const totalAssociations =
fingerprint.strong_associations.length +
fingerprint.weak_associations.length;
if (totalAssociations === 0) return 0.5;
// Simplified assessment - in real implementation, would check actual associations
return Math.min(0.8, 0.4 + (totalAssociations / 10) * 0.4);
}
private async updateRecoveryStatistics(
result: EnhancedRecoveryResult
): Promise<void> {
// Update strategy success rates
for (const attempt of result.recovery_attempts) {
const currentRate =
this.recoveryStatistics.strategy_success_rates.get(
attempt.strategy_name
) ?? 0;
const newRate = attempt.success
? currentRate + 0.1
: Math.max(0, currentRate - 0.05);
this.recoveryStatistics.strategy_success_rates.set(
attempt.strategy_name,
Math.min(1, newRate)
);
}
// Update average recovery time
const totalAttempts = this.recoveryStatistics.total_recovery_attempts;
const currentAvgTime = this.recoveryStatistics.average_recovery_time_ms;
this.recoveryStatistics.average_recovery_time_ms =
(currentAvgTime * totalAttempts + result.recovery_time_ms) /
(totalAttempts + 1);
}
private async updateStrategyLearning(
recovery_result: RecoveryResult,
user_validation: RecoveryValidation
): Promise<void> {
// Adjust strategy confidence based on user validation
const strategyName = recovery_result.recovery_method;
const strategy = this.recoveryStrategies.get(strategyName);
if (strategy && user_validation.user_confirms_accuracy) {
// Positive feedback - increase strategy success rate
const currentRate =
this.recoveryStatistics.strategy_success_rates.get(strategyName) ?? 0;
const adjustment = user_validation.accuracy_rating * 0.1;
this.recoveryStatistics.strategy_success_rates.set(
strategyName,
Math.min(1, currentRate + adjustment)
);
}
}
private async calculateRecoveryTrends(): Promise<RecoveryTrend[]> {
// Simplified trend calculation - in real implementation, would analyze historical data
const trends: RecoveryTrend[] = [];
const successRate =
this.recoveryStatistics.successful_recoveries /
Math.max(1, this.recoveryStatistics.total_recovery_attempts);
trends.push({
metric_name: "success_rate",
trend_direction:
successRate > 0.6
? "improving"
: successRate < 0.4
? "declining"
: "stable",
change_rate: 0.05, // Simplified
time_period_days: 30,
significance: 0.7,
});
return trends;
}
private async identifyFailurePatterns(): Promise<FailurePattern[]> {
// Simplified pattern identification
const patterns: FailurePattern[] = [];
const failureRate =
this.recoveryStatistics.failed_recoveries /
Math.max(1, this.recoveryStatistics.total_recovery_attempts);
if (failureRate > 0.3) {
patterns.push({
pattern_name: "high_failure_rate",
frequency: failureRate,
typical_causes: [
"Insufficient recovery cues",
"Severe memory degradation",
],
suggested_improvements: [
"Preserve more recovery metadata",
"Implement additional recovery strategies",
],
affected_memory_types: ["episodic", "semantic"],
});
}
return patterns;
}
private generateContentHash(content: any): string {
// Simplified hash generation
const contentStr = JSON.stringify(content);
return `hash_${contentStr.length}_${Date.now()}`;
}
}
// Implementation classes for recovery strategies
class AssociativeRecoveryStrategyImpl implements AssociativeRecoveryStrategy {
name!: string;
description!: string;
confidence_threshold!: number;
association_weight!: number;
spreading_activation_depth!: number;
similarity_threshold!: number;
constructor(config: {
name: string;
description: string;
confidence_threshold: number;
association_weight: number;
spreading_activation_depth: number;
similarity_threshold: number;
}) {
Object.assign(this, config);
}
async recover(
_memory_id: string,
recovery_cues: RecoveryCue[],
recovery_metadata: RecoveryMetadata
): Promise<RecoveryAttempt> {
const startTime = Date.now();
// Use associative fingerprint to guide recovery
const fingerprint = recovery_metadata.association_fingerprint;
const associativeCues = recovery_cues.filter(
(cue) => cue.type === "associative"
);
// Simulate associative recovery process
const recoverySuccess =
associativeCues.length > 0 && fingerprint.strong_associations.length > 0;
const confidence = recoverySuccess
? Math.min(
0.9,
0.5 +
associativeCues.length * 0.1 +
fingerprint.strong_associations.length * 0.05
)
: 0.2;
let recoveredContent = null;
const recoveredElements: string[] = [];
const missingElements: string[] = [];
if (recoverySuccess) {
// Simulate content recovery based on associations
recoveredContent = {
content:
recovery_metadata.content_summary + " [recovered via associations]",
associations: fingerprint.strong_associations.slice(0, 3),
confidence: confidence,
};
recoveredElements.push("content", "associations");
} else {
missingElements.push("content", "associations");
}
return {
strategy_name: this.name,
success: recoverySuccess,
recovered_content: recoveredContent,
confidence,
partial_recovery: confidence > 0.3 && confidence < 0.7,
recovered_elements: recoveredElements,
missing_elements: missingElements,
recovery_method_details: `Associative recovery using ${associativeCues.length} cues and ${fingerprint.strong_associations.length} associations`,
processing_time_ms: Date.now() - startTime,
};
}
async assessRecoveryProbability(
recovery_cues: RecoveryCue[],
recovery_metadata: RecoveryMetadata
): Promise<number> {
const associativeCues = recovery_cues.filter(
(cue) => cue.type === "associative"
).length;
const strongAssociations =
recovery_metadata.association_fingerprint.strong_associations.length;
return Math.min(
0.9,
0.3 + associativeCues * 0.1 + strongAssociations * 0.05
);
}
}
class SchemaBasedRecoveryStrategyImpl implements SchemaBasedRecoveryStrategy {
name!: string;
description!: string;
confidence_threshold!: number;
schema_matching_threshold!: number;
pattern_completion_enabled!: boolean;
contextual_inference_weight!: number;
constructor(config: {
name: string;
description: string;
confidence_threshold: number;
schema_matching_threshold: number;
pattern_completion_enabled: boolean;
contextual_inference_weight: number;
}) {
Object.assign(this, config);
}
async recover(
_memory_id: string,
recovery_cues: RecoveryCue[],
recovery_metadata: RecoveryMetadata
): Promise<RecoveryAttempt> {
const startTime = Date.now();
// Use semantic and contextual cues for schema-based recovery
const semanticCues = recovery_cues.filter((cue) => cue.type === "semantic");
const contextualCues = recovery_cues.filter(
(cue) => cue.type === "contextual"
);
const schemaMatch = semanticCues.length > 0 || contextualCues.length > 0;
const confidence = schemaMatch
? Math.min(
0.85,
0.4 + semanticCues.length * 0.1 + contextualCues.length * 0.08
)
: 0.15;
let recoveredContent = null;
const recoveredElements: string[] = [];
const missingElements: string[] = [];
if (schemaMatch && confidence > this.confidence_threshold) {
// Simulate schema-based content reconstruction
recoveredContent = {
content:
recovery_metadata.content_summary +
" [recovered via schema matching]",
schema_elements: semanticCues.map((cue) => cue.value),
context: contextualCues.map((cue) => cue.value),
confidence: confidence,
};
recoveredElements.push("content", "schema", "context");
} else {
missingElements.push("content", "schema", "context");
}
return {
strategy_name: this.name,
success: schemaMatch && confidence > this.confidence_threshold,
recovered_content: recoveredContent,
confidence,
partial_recovery: confidence > 0.3 && confidence < 0.7,
recovered_elements: recoveredElements,
missing_elements: missingElements,
recovery_method_details: `Schema-based recovery using ${semanticCues.length} semantic and ${contextualCues.length} contextual cues`,
processing_time_ms: Date.now() - startTime,
};
}
async assessRecoveryProbability(
recovery_cues: RecoveryCue[],
_recovery_metadata: RecoveryMetadata
): Promise<number> {
const semanticCues = recovery_cues.filter(
(cue) => cue.type === "semantic"
).length;
const contextualCues = recovery_cues.filter(
(cue) => cue.type === "contextual"
).length;
return Math.min(0.85, 0.2 + semanticCues * 0.12 + contextualCues * 0.1);
}
}
class PartialCueRecoveryStrategyImpl implements PartialCueRecoveryStrategy {
name!: string;
description!: string;
confidence_threshold!: number;
minimum_cue_strength!: number;
cue_combination_method!: "weighted_sum" | "max_activation" | "consensus";
temporal_decay_compensation!: boolean;
constructor(config: {
name: string;
description: string;
confidence_threshold: number;
minimum_cue_strength: number;
cue_combination_method: "weighted_sum" | "max_activation" | "consensus";
temporal_decay_compensation: boolean;
}) {
Object.assign(this, config);
}
async recover(
_memory_id: string,
recovery_cues: RecoveryCue[],
recovery_metadata: RecoveryMetadata
): Promise<RecoveryAttempt> {
const startTime = Date.now();
// Filter cues by minimum strength
const strongCues = recovery_cues.filter(
(cue) => cue.strength >= this.minimum_cue_strength
);
// Combine cue strengths based on method
let combinedStrength = 0;
switch (this.cue_combination_method) {
case "weighted_sum":
combinedStrength =
strongCues.reduce((sum, cue) => sum + cue.strength, 0) /
strongCues.length;
break;
case "max_activation":
combinedStrength = Math.max(
...strongCues.map((cue) => cue.strength),
0
);
break;
case "consensus":
combinedStrength =
strongCues.length > 2
? strongCues.reduce((sum, cue) => sum + cue.strength, 0) /
strongCues.length
: 0;
break;
}
// Apply temporal decay compensation if enabled
if (this.temporal_decay_compensation) {
const age = Date.now() - recovery_metadata.original_timestamp;
const daysSinceCreation = age / (1000 * 60 * 60 * 24);
const decayFactor = Math.max(0.5, 1 - (daysSinceCreation / 365) * 0.3);
combinedStrength *= decayFactor;
}
const recoverySuccess = combinedStrength > this.confidence_threshold;
const confidence = Math.min(0.8, combinedStrength);
let recoveredContent = null;
const recoveredElements: string[] = [];
const missingElements: string[] = [];
if (recoverySuccess) {
// Simulate partial content recovery
recoveredContent = {
content:
recovery_metadata.content_summary + " [partial recovery from cues]",
recovered_cues: strongCues.map((cue) => ({
type: cue.type,
value: cue.value,
})),
confidence: confidence,
};
recoveredElements.push("partial_content", "cues");
if (confidence < 0.6) {
missingElements.push("detailed_content");
}
} else {
missingElements.push("content", "cues");
}
return {
strategy_name: this.name,
success: recoverySuccess,
recovered_content: recoveredContent,
confidence,
partial_recovery: confidence > 0.3 && confidence < 0.7,
recovered_elements: recoveredElements,
missing_elements: missingElements,
recovery_method_details: `Partial cue recovery using ${strongCues.length} strong cues with ${this.cue_combination_method} combination`,
processing_time_ms: Date.now() - startTime,
};
}
async assessRecoveryProbability(
recovery_cues: RecoveryCue[],
_recovery_metadata: RecoveryMetadata
): Promise<number> {
const strongCues = recovery_cues.filter(
(cue) => cue.strength >= this.minimum_cue_strength
);
const avgStrength =
strongCues.length > 0
? strongCues.reduce((sum, cue) => sum + cue.strength, 0) /
strongCues.length
: 0;
return Math.min(0.8, avgStrength * 0.8);
}
}