// Copyright 2025 Chris Bunting
// Brief: Progressive disclosure service for MCP Code Analysis & Quality Server
// Scope: Manages context-aware information filtering and progressive detail revelation
import { EventEmitter } from 'events';
import {
AnalysisContext,
UnifiedAnalysisResult,
LoggerInterface,
CacheInterface,
PriorityLevel,
SeverityLevel
} from '@mcp-code-analysis/shared-types';
export interface ProgressiveDisclosureConfig {
enableAdaptation: boolean;
enablePersonalization: boolean;
maxInformationDepth: number;
defaultDetailLevel: DetailLevel;
adaptationThreshold: number;
learningRate: number;
enableContextAwareness: boolean;
enableInteractiveExploration: boolean;
}
export interface DisclosureRequest {
userId: string;
projectId: string;
information: InformationItem[];
context: DisclosureContext;
options: DisclosureOptions;
}
export interface DisclosureResponse {
success: boolean;
disclosedItems: DisclosedItem[];
hiddenItems: HiddenItem[];
reasoning: DisclosureReasoning[];
recommendations: DisclosureRecommendation[];
metadata: DisclosureMetadata;
}
export interface InformationItem {
id: string;
type: InformationType;
title: string;
content: string;
complexity: number;
importance: number;
sensitivity: number;
relevance: number;
dependencies: string[];
metadata: InformationMetadata;
}
export interface DisclosedItem {
id: string;
information: InformationItem;
detailLevel: DetailLevel;
adaptation: AdaptationInfo;
reasoning: string[];
confidence: number;
interactions: Interaction[];
}
export interface HiddenItem {
id: string;
reason: HidingReason;
detailLevel: DetailLevel;
prerequisites: string[];
estimatedRevealTime: Date;
confidence: number;
}
export interface DisclosureContext {
userContext: UserContext;
projectContext: ProjectContext;
temporalContext: TemporalContext;
spatialContext: SpatialContext;
domainContext: DomainContext;
}
export interface DisclosureOptions {
maxDepth: number;
includeReasoning: boolean;
includeRecommendations: boolean;
adaptationStrategy: AdaptationStrategy;
interactionMode: InteractionMode;
}
export interface DisclosureReasoning {
id: string;
type: ReasoningType;
premise: string;
conclusion: string;
confidence: number;
evidence: string[];
}
export interface DisclosureRecommendation {
id: string;
type: RecommendationType;
description: string;
priority: PriorityLevel;
effort: number;
expectedOutcome: string;
confidence: number;
}
export interface DisclosureMetadata {
totalItems: number;
disclosedItems: number;
hiddenItems: number;
averageComplexity: number;
averageImportance: number;
processingTime: number;
adaptationApplied: boolean;
}
export interface UserContext {
expertise: ExpertiseLevel;
preferences: UserPreferences;
history: DisclosureHistory[];
currentFocus: FocusArea;
cognitiveLoad: CognitiveLoad;
}
export interface ProjectContext {
phase: ProjectPhase;
complexity: number;
domain: string;
technologies: string[];
teamContext: TeamContext;
}
export interface TemporalContext {
timeframe: Timeframe;
urgency: UrgencyLevel;
deadline: Date | null;
availableTime: number;
}
export interface SpatialContext {
files: string[];
modules: string[];
components: string[];
currentLocation: string;
}
export interface DomainContext {
businessDomain: string;
technicalDomain: string;
industry: string;
regulations: string[];
}
export interface InformationMetadata {
language: string;
technologies: string[];
patterns: string[];
bestPractices: string[];
createdAt: Date;
updatedAt: Date;
accessCount: number;
}
export interface AdaptationInfo {
originalComplexity: number;
adaptedComplexity: number;
adaptationType: AdaptationType;
factors: AdaptationFactor[];
effectiveness: number;
}
export interface Interaction {
id: string;
type: InteractionType;
timestamp: Date;
userAction: string;
systemResponse: string;
satisfaction: number;
}
export interface UserPreferences {
preferredLanguages: string[];
preferredTechnologies: string[];
detailLevel: DetailLevel;
visualizationPreference: VisualizationType;
learningStyle: LearningStyle;
cognitiveStyle: CognitiveStyle;
}
export interface DisclosureHistory {
timestamp: Date;
informationId: string;
action: DisclosureAction;
detailLevel: DetailLevel;
satisfaction: number;
effectiveness: number;
}
export interface FocusArea {
type: FocusType;
target: string;
priority: number;
duration: number;
}
export interface CognitiveLoad {
current: number;
capacity: number;
factors: CognitiveFactor[];
}
export interface TeamContext {
size: number;
experience: ExperienceLevel;
collaborationStyle: CollaborationStyle;
communication: CommunicationLevel;
}
export interface AdaptationFactor {
type: FactorType;
name: string;
value: number;
weight: number;
description: string;
}
export interface CognitiveFactor {
type: CognitiveFactorType;
name: string;
value: number;
impact: number;
description: string;
}
export enum InformationType {
CODE_ANALYSIS = 'code-analysis',
ARCHITECTURE = 'architecture',
BUSINESS_LOGIC = 'business-logic',
DATA_MODEL = 'data-model',
API_CONTRACT = 'api-contract',
CONFIGURATION = 'configuration',
DEPENDENCY = 'dependency',
TEST_PATTERN = 'test-pattern',
DOCUMENTATION = 'documentation',
PERFORMANCE = 'performance',
SECURITY = 'security',
BEST_PRACTICE = 'best-practice',
ANTI_PATTERN = 'anti-pattern',
DESIGN_PATTERN = 'design-pattern',
REQUIREMENT = 'requirement',
CONSTRAINT = 'constraint'
}
export enum DetailLevel {
OVERVIEW = 'overview',
BASIC = 'basic',
DETAILED = 'detailed',
COMPREHENSIVE = 'comprehensive',
EXPERT = 'expert'
}
export enum HidingReason {
COMPLEXITY = 'complexity',
EXPERTISE = 'expertise',
CONTEXT = 'context',
DEPENDENCY = 'dependency',
SENSITIVITY = 'sensitivity',
RELEVANCE = 'relevance',
COGNITIVE_LOAD = 'cognitive-load',
PRIORITY = 'priority'
}
export enum ReasoningType {
COMPLEXITY_BASED = 'complexity-based',
EXPERTISE_BASED = 'expertise-based',
CONTEXT_AWARE = 'context-aware',
DEPENDENCY_BASED = 'dependency-based',
COGNITIVE_LOAD_BASED = 'cognitive-load-based',
PRIORITY_BASED = 'priority-based'
}
export enum RecommendationType {
LEARN_MORE = 'learn-more',
SIMPLIFY = 'simplify',
POSTPONE = 'postpone',
DELEGATE = 'delegate',
AUTOMATE = 'automate',
COLLABORATE = 'collaborate'
}
export enum AdaptationStrategy {
COMPLEXITY_REDUCTION = 'complexity-reduction',
ABSTRACTION = 'abstraction',
PROGRESSION = 'progression',
PERSONALIZATION = 'personalization',
CONTEXT_AWARE = 'context-aware'
}
export enum InteractionMode {
PASSIVE = 'passive',
INTERACTIVE = 'interactive',
GUIDED = 'guided',
EXPLORATORY = 'exploratory'
}
export enum ExpertiseLevel {
BEGINNER = 'beginner',
INTERMEDIATE = 'intermediate',
ADVANCED = 'advanced',
EXPERT = 'expert'
}
export enum LearningStyle {
VISUAL = 'visual',
AUDITORY = 'auditory',
KINESTHETIC = 'kinesthetic',
READING = 'reading',
MIXED = 'mixed'
}
export enum CognitiveStyle {
ANALYTICAL = 'analytical',
INTUITIVE = 'intuitive',
SEQUENTIAL = 'sequential',
GLOBAL = 'global'
}
export enum DisclosureAction {
REVEAL = 'reveal',
HIDE = 'hide',
EXPAND = 'expand',
COLLAPSE = 'collapse',
NAVIGATE = 'navigate'
}
export enum FocusType {
CODE = 'code',
ARCHITECTURE = 'architecture',
BUSINESS_LOGIC = 'business-logic',
DATA = 'data',
API = 'api',
CONFIGURATION = 'configuration',
TESTING = 'testing',
DOCUMENTATION = 'documentation'
}
export enum ProjectPhase {
PLANNING = 'planning',
DEVELOPMENT = 'development',
TESTING = 'testing',
DEPLOYMENT = 'deployment',
MAINTENANCE = 'maintenance'
}
export enum Timeframe {
IMMEDIATE = 'immediate',
SHORT_TERM = 'short-term',
MEDIUM_TERM = 'medium-term',
LONG_TERM = 'long-term'
}
export enum UrgencyLevel {
LOW = 'low',
MEDIUM = 'medium',
HIGH = 'high',
CRITICAL = 'critical'
}
export enum ExperienceLevel {
JUNIOR = 'junior',
MID = 'mid',
SENIOR = 'senior',
EXPERT = 'expert'
}
export enum CollaborationStyle {
INDEPENDENT = 'independent',
COLLABORATIVE = 'collaborative',
PAIR_PROGRAMMING = 'pair-programming',
MOB_PROGRAMMING = 'mob-programming'
}
export enum CommunicationLevel {
MINIMAL = 'minimal',
MODERATE = 'moderate',
FREQUENT = 'frequent',
CONTINUOUS = 'continuous'
}
export enum AdaptationType {
SIMPLIFICATION = 'simplification',
ABSTRACTION = 'abstraction',
CHUNKING = 'chunking',
VISUALIZATION = 'visualization',
ANNOTATION = 'annotation'
}
export enum FactorType {
USER_EXPERTISE = 'user-expertise',
INFORMATION_COMPLEXITY = 'information-complexity',
CONTEXT_RELEVANCE = 'context-relevance',
COGNITIVE_LOAD = 'cognitive-load',
TIME_PRESSURE = 'time-pressure',
PRIORITY = 'priority'
}
export enum CognitiveFactorType {
WORKING_MEMORY = 'working-memory',
ATTENTION_SPAN = 'attention-span',
PROCESSING_SPEED = 'processing-speed',
COMPREHENSION = 'comprehension'
}
export enum InteractionType {
CLICK = 'click',
HOVER = 'hover',
EXPAND = 'expand',
COLLAPSE = 'collapse',
NAVIGATE = 'navigate',
SEARCH = 'search',
FILTER = 'filter'
}
export enum VisualizationType {
TEXT = 'text',
GRAPH = 'graph',
TREE = 'tree',
TABLE = 'table',
DIAGRAM = 'diagram'
}
export class ProgressiveDisclosureService extends EventEmitter {
private config: ProgressiveDisclosureConfig;
private cache: CacheInterface;
private logger: LoggerInterface;
private userProfiles: Map<string, UserProfile> = new Map();
private disclosureAlgorithms: Map<DisclosureAlgorithmType, DisclosureAlgorithm> = new Map();
private adaptationAlgorithms: Map<AdaptationAlgorithmType, AdaptationAlgorithm> = new Map();
constructor(config: ProgressiveDisclosureConfig, cache: CacheInterface, logger: LoggerInterface) {
super();
this.config = config;
this.cache = cache;
this.logger = logger;
this.setupEventHandlers();
this.initializeAlgorithms();
}
private setupEventHandlers(): void {
this.on('information-disclosed', this.handleInformationDisclosed.bind(this));
this.on('information-hidden', this.handleInformationHidden.bind(this));
this.on('adaptation-applied', this.handleAdaptationApplied.bind(this));
this.on('interaction-recorded', this.handleInteractionRecorded.bind(this));
}
private initializeAlgorithms(): void {
// Initialize disclosure algorithms
this.disclosureAlgorithms.set(DisclosureAlgorithmType.COMPLEXITY_BASED, new ComplexityBasedDisclosureAlgorithm());
this.disclosureAlgorithms.set(DisclosureAlgorithmType.EXPERTISE_BASED, new ExpertiseBasedDisclosureAlgorithm());
this.disclosureAlgorithms.set(DisclosureAlgorithmType.CONTEXT_AWARE, new ContextAwareDisclosureAlgorithm());
this.disclosureAlgorithms.set(DisclosureAlgorithmType.COGNITIVE_LOAD_BASED, new CognitiveLoadBasedDisclosureAlgorithm());
this.disclosureAlgorithms.set(DisclosureAlgorithmType.PRIORITY_BASED, new PriorityBasedDisclosureAlgorithm());
// Initialize adaptation algorithms
this.adaptationAlgorithms.set(AdaptationAlgorithmType.SIMPLIFICATION, new SimplificationAdaptationAlgorithm());
this.adaptationAlgorithms.set(AdaptationAlgorithmType.ABSTRACTION, new AbstractionAdaptationAlgorithm());
this.adaptationAlgorithms.set(AdaptationAlgorithmType.CHUNKING, new ChunkingAdaptationAlgorithm());
this.adaptationAlgorithms.set(AdaptationAlgorithmType.VISUALIZATION, new VisualizationAdaptationAlgorithm());
this.adaptationAlgorithms.set(AdaptationAlgorithmType.PERSONALIZATION, new PersonalizationAdaptationAlgorithm());
}
async initialize(): Promise<void> {
this.logger.info('Initializing Progressive Disclosure Service');
// Load existing user profiles from cache
await this.loadUserProfiles();
this.logger.info('Progressive Disclosure Service initialized successfully');
}
async discloseInformation(request: DisclosureRequest): Promise<DisclosureResponse> {
try {
this.logger.info(`Processing disclosure request for user: ${request.userId}`);
const startTime = Date.now();
// Get or create user profile
let userProfile = this.userProfiles.get(request.userId);
if (!userProfile) {
userProfile = await this.createUserProfile(request.userId, request.context.userContext);
}
// Analyze information and determine disclosure strategy
const analysis = await this.analyzeInformation(request, userProfile);
// Apply disclosure algorithms
const disclosureResult = await this.applyDisclosureAlgorithms(request, analysis, userProfile);
// Apply adaptation if enabled
let adaptationApplied = false;
if (this.config.enableAdaptation) {
const adaptationResult = await this.applyAdaptation(disclosureResult.disclosedItems, request, userProfile);
disclosureResult.disclosedItems = adaptationResult.adaptedItems;
adaptationApplied = adaptationResult.adaptationApplied;
}
// Generate reasoning and recommendations
const reasoning = await this.generateReasoning(disclosureResult, request, userProfile);
const recommendations = await this.generateRecommendations(disclosureResult, request, userProfile);
// Create response
const response: DisclosureResponse = {
success: true,
disclosedItems: disclosureResult.disclosedItems,
hiddenItems: disclosureResult.hiddenItems,
reasoning,
recommendations,
metadata: {
totalItems: request.information.length,
disclosedItems: disclosureResult.disclosedItems.length,
hiddenItems: disclosureResult.hiddenItems.length,
averageComplexity: this.calculateAverageComplexity(disclosureResult.disclosedItems),
averageImportance: this.calculateAverageImportance(disclosureResult.disclosedItems),
processingTime: Date.now() - startTime,
adaptationApplied
}
};
// Update user profile with interaction history
await this.updateUserProfile(userProfile, request, response);
// Save updated profile
await this.saveUserProfile(userProfile.id);
this.emit('information-disclosed', {
userId: request.userId,
projectId: request.projectId,
disclosedCount: response.disclosedItems.length,
hiddenCount: response.hiddenItems.length
});
this.logger.info(`Successfully processed disclosure request for user: ${request.userId}`);
return response;
} catch (error) {
this.logger.error('Failed to disclose information:', error);
return {
success: false,
disclosedItems: [],
hiddenItems: [],
reasoning: [],
recommendations: [],
metadata: {
totalItems: 0,
disclosedItems: 0,
hiddenItems: 0,
averageComplexity: 0,
averageImportance: 0,
processingTime: 0,
adaptationApplied: false
}
};
}
}
async recordInteraction(interaction: InteractionRecord): Promise<boolean> {
try {
this.logger.info(`Recording interaction for user: ${interaction.userId}`);
const userProfile = this.userProfiles.get(interaction.userId);
if (!userProfile) {
throw new Error(`User profile not found: ${interaction.userId}`);
}
// Update user history
const historyEntry: DisclosureHistory = {
timestamp: interaction.timestamp,
informationId: interaction.informationId,
action: interaction.action,
detailLevel: interaction.detailLevel,
satisfaction: interaction.satisfaction,
effectiveness: interaction.effectiveness
};
userProfile.context.history.push(historyEntry);
// Update user preferences based on interaction
if (this.config.enablePersonalization) {
await this.updateUserPreferences(userProfile, interaction);
}
// Update cognitive load
await this.updateCognitiveLoad(userProfile, interaction);
// Save updated profile
await this.saveUserProfile(userProfile.id);
this.emit('interaction-recorded', {
userId: interaction.userId,
action: interaction.action,
satisfaction: interaction.satisfaction
});
this.logger.info(`Successfully recorded interaction for user: ${interaction.userId}`);
return true;
} catch (error) {
this.logger.error('Failed to record interaction:', error);
return false;
}
}
async getUserProfile(userId: string): Promise<UserProfile | null> {
return this.userProfiles.get(userId) || null;
}
async updateUserPreferences(userId: string, preferences: Partial<UserPreferences>): Promise<boolean> {
try {
const userProfile = this.userProfiles.get(userId);
if (!userProfile) {
throw new Error(`User profile not found: ${userId}`);
}
userProfile.context.preferences = { ...userProfile.context.preferences, ...preferences };
userProfile.updatedAt = new Date();
await this.saveUserProfile(userId);
this.logger.info(`Successfully updated preferences for user: ${userId}`);
return true;
} catch (error) {
this.logger.error('Failed to update user preferences:', error);
return false;
}
}
private async createUserProfile(userId: string, userContext: UserContext): Promise<UserProfile> {
const profile: UserProfile = {
id: userId,
context: userContext,
createdAt: new Date(),
updatedAt: new Date()
};
this.userProfiles.set(userId, profile);
await this.saveUserProfile(userId);
this.emit('user-profile-created', profile);
this.logger.info(`User profile created for user: ${userId}`);
return profile;
}
private async analyzeInformation(request: DisclosureRequest, userProfile: UserProfile): Promise<InformationAnalysis> {
const analysis: InformationAnalysis = {
complexityScore: 0,
relevanceScore: 0,
cognitiveLoadEstimate: 0,
dependencies: new Map<string, string[]>(),
shouldAdapt: false,
adaptationFactors: []
};
// Calculate complexity score
analysis.complexityScore = request.information.reduce((sum, item) => sum + item.complexity, 0) / request.information.length;
// Calculate relevance score
analysis.relevanceScore = request.information.reduce((sum, item) => sum + item.relevance, 0) / request.information.length;
// Estimate cognitive load
analysis.cognitiveLoadEstimate = await this.estimateCognitiveLoad(request, userProfile);
// Analyze dependencies
for (const item of request.information) {
analysis.dependencies.set(item.id, item.dependencies);
}
// Determine if adaptation is needed
analysis.shouldAdapt = analysis.complexityScore > 7 ||
analysis.cognitiveLoadEstimate > userProfile.context.cognitiveLoad.capacity * 0.8;
// Identify adaptation factors
if (analysis.shouldAdapt) {
analysis.adaptationFactors = await this.identifyAdaptationFactors(request, userProfile, analysis);
}
return analysis;
}
private async applyDisclosureAlgorithms(
request: DisclosureRequest,
analysis: InformationAnalysis,
userProfile: UserProfile
): Promise<DisclosureResult> {
const disclosedItems: DisclosedItem[] = [];
const hiddenItems: HiddenItem[] = [];
for (const item of request.information) {
const disclosureDecision = await this.makeDisclosureDecision(item, request, analysis, userProfile);
if (disclosureDecision.shouldDisclose) {
const disclosedItem: DisclosedItem = {
id: item.id,
information: item,
detailLevel: disclosureDecision.detailLevel,
adaptation: disclosureDecision.adaptation || {
originalComplexity: item.complexity,
adaptedComplexity: item.complexity,
adaptationType: AdaptationType.SIMPLIFICATION,
factors: [],
effectiveness: 1.0
},
reasoning: disclosureDecision.reasoning,
confidence: disclosureDecision.confidence,
interactions: []
};
disclosedItems.push(disclosedItem);
} else {
const hiddenItem: HiddenItem = {
id: item.id,
reason: disclosureDecision.hidingReason,
detailLevel: disclosureDecision.detailLevel,
prerequisites: disclosureDecision.prerequisites,
estimatedRevealTime: disclosureDecision.estimatedRevealTime,
confidence: disclosureDecision.confidence
};
hiddenItems.push(hiddenItem);
}
}
return { disclosedItems, hiddenItems };
}
private async makeDisclosureDecision(
item: InformationItem,
request: DisclosureRequest,
analysis: InformationAnalysis,
userProfile: UserProfile
): Promise<DisclosureDecision> {
let shouldDisclose = true;
let hidingReason: HidingReason | null = null;
let detailLevel = this.config.defaultDetailLevel;
let confidence = 0.5;
let reasoning: string[] = [];
let prerequisites: string[] = [];
let estimatedRevealTime = new Date();
let adaptation: AdaptationInfo | null = null;
// Apply disclosure algorithms
for (const [type, algorithm] of this.disclosureAlgorithms) {
try {
const result = await algorithm.shouldDisclose(item, request, analysis, userProfile);
if (!result.shouldDisclose) {
shouldDisclose = false;
hidingReason = result.reason;
detailLevel = result.detailLevel;
prerequisites = result.prerequisites;
estimatedRevealTime = result.estimatedRevealTime;
}
confidence = Math.max(confidence, result.confidence);
reasoning.push(...result.reasoning);
if (result.adaptation) {
adaptation = result.adaptation;
}
} catch (error) {
this.logger.warn(`Failed to apply disclosure algorithm ${type}:`, error);
}
}
// Apply depth limit
if (request.options.maxDepth > 0) {
const currentDepth = this.detailLevelToDepth(detailLevel);
if (currentDepth > request.options.maxDepth) {
shouldDisclose = false;
hidingReason = HidingReason.COMPLEXITY;
detailLevel = this.depthToDetailLevel(request.options.maxDepth);
reasoning.push('Depth limit exceeded');
}
}
return {
shouldDisclose,
hidingReason,
detailLevel,
confidence,
reasoning,
prerequisites,
estimatedRevealTime,
adaptation
};
}
private async applyAdaptation(
disclosedItems: DisclosedItem[],
request: DisclosureRequest,
userProfile: UserProfile
): Promise<AdaptationResult> {
let adaptationApplied = false;
const adaptedItems: DisclosedItem[] = [];
for (const item of disclosedItems) {
let shouldAdapt = false;
let bestAdaptation: AdaptationInfo | null = null;
let bestEffectiveness = 0;
// Try each adaptation algorithm
for (const [type, algorithm] of this.adaptationAlgorithms) {
try {
const result = await algorithm.shouldAdapt(item, request, userProfile);
if (result.shouldAdapt && result.effectiveness > bestEffectiveness) {
shouldAdapt = true;
bestAdaptation = result.adaptation;
bestEffectiveness = result.effectiveness;
}
} catch (error) {
this.logger.warn(`Failed to apply adaptation algorithm ${type}:`, error);
}
}
if (shouldAdapt && bestAdaptation) {
item.adaptation = bestAdaptation;
adaptationApplied = true;
}
adaptedItems.push(item);
}
return { adaptedItems, adaptationApplied };
}
private async generateReasoning(
result: DisclosureResult,
request: DisclosureRequest,
userProfile: UserProfile
): Promise<DisclosureReasoning[]> {
const reasoning: DisclosureReasoning[] = [];
// Generate reasoning for disclosed items
for (const item of result.disclosedItems) {
const reasoningEntry: DisclosureReasoning = {
id: this.generateReasoningId(),
type: ReasoningType.COMPLEXITY_BASED,
premise: `Item complexity: ${item.information.complexity}, User expertise: ${userProfile.context.expertise}`,
conclusion: `Item disclosed at ${item.detailLevel} level`,
confidence: item.confidence,
evidence: item.reasoning
};
reasoning.push(reasoningEntry);
}
// Generate reasoning for hidden items
for (const item of result.hiddenItems) {
const reasoningEntry: DisclosureReasoning = {
id: this.generateReasoningId(),
type: ReasoningType.EXPERTISE_BASED,
premise: `Item hidden due to ${item.reason}`,
conclusion: `Item will be revealed when prerequisites are met`,
confidence: item.confidence,
evidence: [`Prerequisites: ${item.prerequisites.join(', ')}`]
};
reasoning.push(reasoningEntry);
}
return reasoning;
}
private async generateRecommendations(
result: DisclosureResult,
request: DisclosureRequest,
userProfile: UserProfile
): Promise<DisclosureRecommendation[]> {
const recommendations: DisclosureRecommendation[] = [];
// Generate recommendations based on hidden items
for (const item of result.hiddenItems) {
switch (item.reason) {
case HidingReason.COMPLEXITY:
recommendations.push({
id: this.generateRecommendationId(),
type: RecommendationType.SIMPLIFY,
description: `Consider simplifying the information for better understanding`,
priority: PriorityLevel.MEDIUM,
effort: 3,
expectedOutcome: 'Improved comprehension and reduced cognitive load',
confidence: 0.8
});
break;
case HidingReason.EXPERTISE:
recommendations.push({
id: this.generateRecommendationId(),
type: RecommendationType.LEARN_MORE,
description: `Consider learning prerequisites to access this information`,
priority: PriorityLevel.LOW,
effort: 5,
expectedOutcome: 'Access to more detailed information',
confidence: 0.7
});
break;
case HidingReason.COGNITIVE_LOAD:
recommendations.push({
id: this.generateRecommendationId(),
type: RecommendationType.POSTPONE,
description: `Consider reviewing this information when cognitive load is lower`,
priority: PriorityLevel.MEDIUM,
effort: 1,
expectedOutcome: 'Better information retention and understanding',
confidence: 0.9
});
break;
}
}
// Generate recommendations based on adaptation effectiveness
if (result.disclosedItems.some(item => item.adaptation.effectiveness < 0.7)) {
recommendations.push({
id: this.generateRecommendationId(),
type: RecommendationType.AUTOMATE,
description: 'Consider automating information adaptation for better effectiveness',
priority: PriorityLevel.HIGH,
effort: 7,
expectedOutcome: 'Improved adaptation effectiveness and user experience',
confidence: 0.8
});
}
return recommendations;
}
private async updateUserPreferences(userProfile: UserProfile, interaction: InteractionRecord): Promise<void> {
// Update preferences based on interaction patterns
if (interaction.satisfaction > 0.8) {
// User is satisfied with current detail level
userProfile.context.preferences.detailLevel = interaction.detailLevel;
}
// Update visualization preference based on interaction type
if (interaction.action === DisclosureAction.NAVIGATE) {
userProfile.context.preferences.visualizationPreference = VisualizationType.GRAPH;
}
}
private async updateCognitiveLoad(userProfile: UserProfile, interaction: InteractionRecord): Promise<void> {
// Update cognitive load based on interaction effectiveness
const loadChange = (1 - interaction.effectiveness) * 0.2;
userProfile.context.cognitiveLoad.current = Math.min(
userProfile.context.cognitiveLoad.capacity,
userProfile.context.cognitiveLoad.current + loadChange
);
// Gradually reduce cognitive load over time
setTimeout(() => {
userProfile.context.cognitiveLoad.current = Math.max(
0,
userProfile.context.cognitiveLoad.current - 0.1
);
}, 5000);
}
private async updateUserProfile(userProfile: UserProfile, request: DisclosureRequest, response: DisclosureResponse): Promise<void> {
// Update user profile with disclosure history
for (const item of response.disclosedItems) {
const historyEntry: DisclosureHistory = {
timestamp: new Date(),
informationId: item.id,
action: DisclosureAction.REVEAL,
detailLevel: item.detailLevel,
satisfaction: 0.8, // Default satisfaction
effectiveness: item.confidence
};
userProfile.context.history.push(historyEntry);
}
userProfile.updatedAt = new Date();
}
private async estimateCognitiveLoad(request: DisclosureRequest, userProfile: UserProfile): Promise<number> {
let estimatedLoad = 0;
// Base load from information complexity
const complexityLoad = request.information.reduce((sum, item) => sum + item.complexity, 0) / request.information.length;
// Adjust based on user expertise
const expertiseMultiplier = {
[ExpertiseLevel.BEGINNER]: 1.5,
[ExpertiseLevel.INTERMEDIATE]: 1.2,
[ExpertiseLevel.ADVANCED]: 1.0,
[ExpertiseLevel.EXPERT]: 0.8
};
estimatedLoad = complexityLoad * expertiseMultiplier[userProfile.context.expertise];
// Adjust based on time pressure
if (request.context.temporalContext.urgency === UrgencyLevel.HIGH) {
estimatedLoad *= 1.3;
}
// Adjust based on current cognitive load
const currentLoadRatio = userProfile.context.cognitiveLoad.current / userProfile.context.cognitiveLoad.capacity;
if (currentLoadRatio > 0.8) {
estimatedLoad *= 1.5;
}
return Math.min(10, estimatedLoad);
}
private async identifyAdaptationFactors(
request: DisclosureRequest,
userProfile: UserProfile,
analysis: InformationAnalysis
): Promise<AdaptationFactor[]> {
const factors: AdaptationFactor[] = [];
// User expertise factor
factors.push({
type: FactorType.USER_EXPERTISE,
name: 'User Expertise',
value: this.expertiseToValue(userProfile.context.expertise),
weight: 0.3,
description: 'User\'s level of expertise affects information complexity tolerance'
});
// Information complexity factor
factors.push({
type: FactorType.INFORMATION_COMPLEXITY,
name: 'Information Complexity',
value: analysis.complexityScore,
weight: 0.4,
description: 'Complexity of the information being disclosed'
});
// Cognitive load factor
factors.push({
type: FactorType.COGNITIVE_LOAD,
name: 'Cognitive Load',
value: analysis.cognitiveLoadEstimate,
weight: 0.3,
description: 'Current cognitive load of the user'
});
return factors;
}
private expertiseToValue(expertise: ExpertiseLevel): number {
const valueMap = {
[ExpertiseLevel.BEGINNER]: 0.2,
[ExpertiseLevel.INTERMEDIATE]: 0.5,
[ExpertiseLevel.ADVANCED]: 0.8,
[ExpertiseLevel.EXPERT]: 1.0
};
return valueMap[expertise];
}
private detailLevelToDepth(detailLevel: DetailLevel): number {
const depthMap = {
[DetailLevel.OVERVIEW]: 1,
[DetailLevel.BASIC]: 2,
[DetailLevel.DETAILED]: 3,
[DetailLevel.COMPREHENSIVE]: 4,
[DetailLevel.EXPERT]: 5
};
return depthMap[detailLevel];
}
private depthToDetailLevel(depth: number): DetailLevel {
const levelMap = {
1: DetailLevel.OVERVIEW,
2: DetailLevel.BASIC,
3: DetailLevel.DETAILED,
4: DetailLevel.COMPREHENSIVE,
5: DetailLevel.EXPERT
};
return levelMap[Math.min(5, Math.max(1, depth))];
}
private calculateAverageComplexity(items: DisclosedItem[]): number {
if (items.length === 0) return 0;
const totalComplexity = items.reduce((sum, item) => sum + item.information.complexity, 0);
return totalComplexity / items.length;
}
private calculateAverageImportance(items: DisclosedItem[]): number {
if (items.length === 0) return 0;
const totalImportance = items.reduce((sum, item) => sum + item.information.importance, 0);
return totalImportance / items.length;
}
private async loadUserProfiles(): Promise<void> {
try {
const cachedProfiles = await this.cache.get<Map<string, any>>('user-profiles-disclosure');
if (cachedProfiles) {
for (const [userId, profileData] of Object.entries(cachedProfiles)) {
this.userProfiles.set(userId, profileData);
}
}
this.logger.info(`Loaded ${this.userProfiles.size} user profiles`);
} catch (error) {
this.logger.warn('Failed to load user profiles:', error);
}
}
private async saveUserProfile(userId: string): Promise<void> {
try {
const profile = this.userProfiles.get(userId);
if (profile) {
await this.cache.set(`user-profile-disclosure-${userId}`, profile, 3600);
// Also save to global profiles index
const profilesIndex: Record<string, any> = {};
for (const [uid, p] of this.userProfiles.entries()) {
profilesIndex[uid] = p;
}
await this.cache.set('user-profiles-disclosure', profilesIndex, 3600);
}
} catch (error) {
this.logger.warn(`Failed to save user profile for user ${userId}:`, error);
}
}
// ID generation methods
private generateReasoningId(): string {
return `reasoning_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
private generateRecommendationId(): string {
return `recommendation_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// Event handlers
private handleInformationDisclosed(data: any): void {
this.logger.debug(`Information disclosed event handled for user: ${data.userId}`);
}
private handleInformationHidden(data: any): void {
this.logger.debug(`Information hidden event handled`);
}
private handleAdaptationApplied(data: any): void {
this.logger.debug(`Adaptation applied event handled`);
}
private handleInteractionRecorded(data: any): void {
this.logger.debug(`Interaction recorded event handled for user: ${data.userId}`);
}
// Public API methods
async updateConfig(config: Partial<ProgressiveDisclosureConfig>): Promise<void> {
this.config = { ...this.config, ...config };
this.logger.info('Progressive disclosure configuration updated');
}
async getDisclosureStats(): Promise<any> {
const totalUsers = this.userProfiles.size;
const totalInteractions = Array.from(this.userProfiles.values())
.reduce((sum, profile) => sum + profile.context.history.length, 0);
const averageSatisfaction = Array.from(this.userProfiles.values())
.reduce((sum, profile) => {
const userSatisfaction = profile.context.history.reduce((userSum, history) =>
userSum + history.satisfaction, 0
);
return sum + (userSatisfaction / Math.max(1, profile.context.history.length));
}, 0) / Math.max(1, this.userProfiles.size);
return {
totalUsers,
totalInteractions,
averageSatisfaction,
adaptationEnabled: this.config.enableAdaptation,
personalizationEnabled: this.config.enablePersonalization,
disclosureAlgorithms: this.disclosureAlgorithms.size,
adaptationAlgorithms: this.adaptationAlgorithms.size
};
}
async shutdown(): Promise<void> {
this.logger.info('Shutting down Progressive Disclosure Service');
// Save all user profiles
for (const userId of this.userProfiles.keys()) {
await this.saveUserProfile(userId);
}
// Clear event listeners
this.removeAllListeners();
this.logger.info('Progressive Disclosure Service shutdown complete');
}
}
// Type definitions for intermediate results
interface InformationAnalysis {
complexityScore: number;
relevanceScore: number;
cognitiveLoadEstimate: number;
dependencies: Map<string, string[]>;
shouldAdapt: boolean;
adaptationFactors: AdaptationFactor[];
}
interface DisclosureResult {
disclosedItems: DisclosedItem[];
hiddenItems: HiddenItem[];
}
interface DisclosureDecision {
shouldDisclose: boolean;
hidingReason: HidingReason | null;
detailLevel: DetailLevel;
confidence: number;
reasoning: string[];
prerequisites: string[];
estimatedRevealTime: Date;
adaptation: AdaptationInfo | null;
}
interface AdaptationResult {
adaptedItems: DisclosedItem[];
adaptationApplied: boolean;
}
interface UserProfile {
id: string;
context: UserContext;
createdAt: Date;
updatedAt: Date;
}
interface InteractionRecord {
userId: string;
informationId: string;
timestamp: Date;
action: DisclosureAction;
detailLevel: DetailLevel;
satisfaction: number;
effectiveness: number;
}
// Algorithm type definitions
enum DisclosureAlgorithmType {
COMPLEXITY_BASED = 'complexity-based',
EXPERTISE_BASED = 'expertise-based',
CONTEXT_AWARE = 'context-aware',
COGNITIVE_LOAD_BASED = 'cognitive-load-based',
PRIORITY_BASED = 'priority-based'
}
enum AdaptationAlgorithmType {
SIMPLIFICATION = 'simplification',
ABSTRACTION = 'abstraction',
CHUNKING = 'chunking',
VISUALIZATION = 'visualization',
PERSONALIZATION = 'personalization'
}
// Abstract base classes for algorithms
abstract class DisclosureAlgorithm {
abstract shouldDisclose(
item: InformationItem,
request: DisclosureRequest,
analysis: InformationAnalysis,
userProfile: UserProfile
): Promise<DisclosureAlgorithmResult>;
}
abstract class AdaptationAlgorithm {
abstract shouldAdapt(
item: DisclosedItem,
request: DisclosureRequest,
userProfile: UserProfile
): Promise<AdaptationAlgorithmResult>;
}
// Result type definitions
interface DisclosureAlgorithmResult {
shouldDisclose: boolean;
reason: HidingReason;
detailLevel: DetailLevel;
confidence: number;
reasoning: string[];
prerequisites: string[];
estimatedRevealTime: Date;
adaptation: AdaptationInfo | null;
}
interface AdaptationAlgorithmResult {
shouldAdapt: boolean;
adaptation: AdaptationInfo;
effectiveness: number;
}
// Concrete algorithm implementations (simplified)
class ComplexityBasedDisclosureAlgorithm extends DisclosureAlgorithm {
async shouldDisclose(
item: InformationItem,
request: DisclosureRequest,
analysis: InformationAnalysis,
userProfile: UserProfile
): Promise<DisclosureAlgorithmResult> {
const complexityThreshold = this.getComplexityThreshold(userProfile.context.expertise);
if (item.complexity > complexityThreshold) {
return {
shouldDisclose: false,
reason: HidingReason.COMPLEXITY,
detailLevel: DetailLevel.OVERVIEW,
confidence: 0.8,
reasoning: ['Information complexity exceeds user expertise threshold'],
prerequisites: [],
estimatedRevealTime: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24 hours
adaptation: null
};
}
return {
shouldDisclose: true,
reason: HidingReason.COMPLEXITY,
detailLevel: this.getDetailLevelForComplexity(item.complexity),
confidence: 0.9,
reasoning: ['Information complexity within acceptable range'],
prerequisites: [],
estimatedRevealTime: new Date(),
adaptation: null
};
}
private getComplexityThreshold(expertise: ExpertiseLevel): number {
const thresholds = {
[ExpertiseLevel.BEGINNER]: 3,
[ExpertiseLevel.INTERMEDIATE]: 5,
[ExpertiseLevel.ADVANCED]: 7,
[ExpertiseLevel.EXPERT]: 9
};
return thresholds[expertise];
}
private getDetailLevelForComplexity(complexity: number): DetailLevel {
if (complexity <= 2) return DetailLevel.OVERVIEW;
if (complexity <= 4) return DetailLevel.BASIC;
if (complexity <= 6) return DetailLevel.DETAILED;
if (complexity <= 8) return DetailLevel.COMPREHENSIVE;
return DetailLevel.EXPERT;
}
}
class ExpertiseBasedDisclosureAlgorithm extends DisclosureAlgorithm {
async shouldDisclose(
item: InformationItem,
request: DisclosureRequest,
analysis: InformationAnalysis,
userProfile: UserProfile
): Promise<DisclosureAlgorithmResult> {
const expertiseMatch = this.calculateExpertiseMatch(item, userProfile);
if (expertiseMatch < 0.5) {
return {
shouldDisclose: false,
reason: HidingReason.EXPERTISE,
detailLevel: DetailLevel.OVERVIEW,
confidence: 0.7,
reasoning: ['Information requires higher expertise level'],
prerequisites: this.getPrerequisitesForExpertise(item, userProfile),
estimatedRevealTime: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
adaptation: null
};
}
return {
shouldDisclose: true,
reason: HidingReason.EXPERTISE,
detailLevel: this.getDetailLevelForExpertise(expertiseMatch),
confidence: 0.8,
reasoning: ['Information matches user expertise level'],
prerequisites: [],
estimatedRevealTime: new Date(),
adaptation: null
};
}
private calculateExpertiseMatch(item: InformationItem, userProfile: UserProfile): number {
// Simplified expertise matching logic
const userExpertiseValue = this.expertiseToValue(userProfile.context.expertise);
const requiredExpertise = item.complexity / 10;
return Math.min(1, userExpertiseValue / requiredExpertise);
}
private getPrerequisitesForExpertise(item: InformationItem, userProfile: UserProfile): string[] {
// Generate prerequisites based on expertise gap
const gap = item.complexity - this.expertiseToValue(userProfile.context.expertise) * 10;
if (gap > 5) {
return ['Complete basic training', 'Gain intermediate experience'];
} else if (gap > 2) {
return ['Review related concepts', 'Practice with examples'];
}
return [];
}
private getDetailLevelForExpertise(expertiseMatch: number): DetailLevel {
if (expertiseMatch >= 0.9) return DetailLevel.EXPERT;
if (expertiseMatch >= 0.7) return DetailLevel.COMPREHENSIVE;
if (expertiseMatch >= 0.5) return DetailLevel.DETAILED;
if (expertiseMatch >= 0.3) return DetailLevel.BASIC;
return DetailLevel.OVERVIEW;
}
private expertiseToValue(expertise: ExpertiseLevel): number {
const valueMap = {
[ExpertiseLevel.BEGINNER]: 0.2,
[ExpertiseLevel.INTERMEDIATE]: 0.5,
[ExpertiseLevel.ADVANCED]: 0.8,
[ExpertiseLevel.EXPERT]: 1.0
};
return valueMap[expertise];
}
}
// Additional algorithm implementations would follow similar patterns...
class ContextAwareDisclosureAlgorithm extends DisclosureAlgorithm {
async shouldDisclose(
item: InformationItem,
request: DisclosureRequest,
analysis: InformationAnalysis,
userProfile: UserProfile
): Promise<DisclosureAlgorithmResult> {
// Implement context-aware disclosure logic
return {
shouldDisclose: true,
reason: HidingReason.COMPLEXITY,
detailLevel: DetailLevel.BASIC,
confidence: 0.7,
reasoning: ['Context-aware disclosure applied'],
prerequisites: [],
estimatedRevealTime: new Date(),
adaptation: null
};
}
}
class CognitiveLoadBasedDisclosureAlgorithm extends DisclosureAlgorithm {
async shouldDisclose(
item: InformationItem,
request: DisclosureRequest,
analysis: InformationAnalysis,
userProfile: UserProfile
): Promise<DisclosureAlgorithmResult> {
// Implement cognitive load-based disclosure logic
return {
shouldDisclose: true,
reason: HidingReason.COMPLEXITY,
detailLevel: DetailLevel.BASIC,
confidence: 0.8,
reasoning: ['Cognitive load-based disclosure applied'],
prerequisites: [],
estimatedRevealTime: new Date(),
adaptation: null
};
}
}
class PriorityBasedDisclosureAlgorithm extends DisclosureAlgorithm {
async shouldDisclose(
item: InformationItem,
request: DisclosureRequest,
analysis: InformationAnalysis,
userProfile: UserProfile
): Promise<DisclosureAlgorithmResult> {
// Implement priority-based disclosure logic
return {
shouldDisclose: true,
reason: HidingReason.COMPLEXITY,
detailLevel: DetailLevel.BASIC,
confidence: 0.9,
reasoning: ['Priority-based disclosure applied'],
prerequisites: [],
estimatedRevealTime: new Date(),
adaptation: null
};
}
}
class SimplificationAdaptationAlgorithm extends AdaptationAlgorithm {
async shouldAdapt(
item: DisclosedItem,
request: DisclosureRequest,
userProfile: UserProfile
): Promise<AdaptationAlgorithmResult> {
// Implement simplification adaptation logic
return {
shouldAdapt: item.information.complexity > 7,
adaptation: {
originalComplexity: item.information.complexity,
adaptedComplexity: Math.max(1, item.information.complexity - 3),
adaptationType: AdaptationType.SIMPLIFICATION,
factors: [{
type: FactorType.INFORMATION_COMPLEXITY,
name: 'Complexity Reduction',
value: 3,
weight: 1.0,
description: 'Reduced information complexity by 3 points'
}],
effectiveness: 0.8
},
effectiveness: 0.8
};
}
}
class AbstractionAdaptationAlgorithm extends AdaptationAlgorithm {
async shouldAdapt(
item: DisclosedItem,
request: DisclosureRequest,
userProfile: UserProfile
): Promise<AdaptationAlgorithmResult> {
// Implement abstraction adaptation logic
return {
shouldAdapt: false,
adaptation: {
originalComplexity: item.information.complexity,
adaptedComplexity: item.information.complexity,
adaptationType: AdaptationType.ABSTRACTION,
factors: [],
effectiveness: 1.0
},
effectiveness: 1.0
};
}
}
class ChunkingAdaptationAlgorithm extends AdaptationAlgorithm {
async shouldAdapt(
item: DisclosedItem,
request: DisclosureRequest,
userProfile: UserProfile
): Promise<AdaptationAlgorithmResult> {
// Implement chunking adaptation logic
return {
shouldAdapt: item.information.complexity > 6,
adaptation: {
originalComplexity: item.information.complexity,
adaptedComplexity: Math.max(1, item.information.complexity - 2),
adaptationType: AdaptationType.CHUNKING,
factors: [{
type: FactorType.INFORMATION_COMPLEXITY,
name: 'Information Chunking',
value: 2,
weight: 1.0,
description: 'Chunked information into manageable pieces'
}],
effectiveness: 0.7
},
effectiveness: 0.7
};
}
}
class VisualizationAdaptationAlgorithm extends AdaptationAlgorithm {
async shouldAdapt(
item: DisclosedItem,
request: DisclosureRequest,
userProfile: UserProfile
): Promise<AdaptationAlgorithmResult> {
// Implement visualization adaptation logic
return {
shouldAdapt: userProfile.context.preferences.visualizationPreference === VisualizationType.GRAPH,
adaptation: {
originalComplexity: item.information.complexity,
adaptedComplexity: Math.max(1, item.information.complexity - 1),
adaptationType: AdaptationType.VISUALIZATION,
factors: [{
type: FactorType.USER_EXPERTISE,
name: 'Visual Learning',
value: 1,
weight: 1.0,
description: 'Applied visual learning adaptation'
}],
effectiveness: 0.9
},
effectiveness: 0.9
};
}
}
class PersonalizationAdaptationAlgorithm extends AdaptationAlgorithm {
async shouldAdapt(
item: DisclosedItem,
request: DisclosureRequest,
userProfile: UserProfile
): Promise<AdaptationAlgorithmResult> {
// Implement personalization adaptation logic
return {
shouldAdapt: true,
adaptation: {
originalComplexity: item.information.complexity,
adaptedComplexity: item.information.complexity,
adaptationType: AdaptationType.PERSONALIZATION,
factors: [{
type: FactorType.USER_EXPERTISE,
name: 'Personalization',
value: 1,
weight: 1.0,
description: 'Applied personalization based on user preferences'
}],
effectiveness: 0.85
},
effectiveness: 0.85
};
}
}