/**
* Response Simulator for Debug Tools
*
* Simulates human responses with realistic timing and variations
* to test UI behavior during development.
*/
import { MockServer, MockRequest } from './mock-server.js';
import { mockResponses } from './mock-data.js';
export interface SimulationConfig {
/** Delay before sending response (milliseconds) */
responseDelay: number;
/** Whether to simulate typing delays */
simulateTyping: boolean;
/** Probability of different completion statuses */
completionProbability: {
done: number;
drillDeeper: number;
abort: number;
};
}
export class ResponseSimulator {
private server: MockServer;
private config: SimulationConfig;
constructor(server: MockServer, config: Partial<SimulationConfig> = {}) {
this.server = server;
this.config = {
responseDelay: 3000, // 3 seconds default
simulateTyping: false,
completionProbability: { done: 0.7, drillDeeper: 0.2, abort: 0.1 },
...config
};
// Listen for new requests and auto-respond
this.server.on('response', (data) => {
this.handleResponse(data.request, data.response);
});
}
/**
* Start automatic response simulation for a specific tool type
*/
async simulateResponse(request: MockRequest, customResponse?: any): Promise<any> {
console.error(`[Response Simulator] Simulating response for ${request.type}...`);
// Wait for response delay
await this.delay(this.config.responseDelay);
// Get mock response based on tool type
const response = customResponse || this.getMockResponse(request.type);
console.error(`[Response Simulator] Sending mock response for ${request.type}`);
return response;
}
/**
* Get appropriate mock response for tool type
*/
private getMockResponse(toolType: string): any {
switch (toolType) {
case 'ask-one-question':
return mockResponses.askOneQuestion;
case 'ask-multiple-choice':
return mockResponses.askMultipleChoice;
case 'challenge-hypothesis':
return mockResponses.challengeHypothesis;
case 'choose-next':
return mockResponses.chooseNext;
default:
throw new Error(`Unknown tool type: ${toolType}`);
}
}
/**
* Handle response received from UI
*/
private handleResponse(request: MockRequest, response: any): void {
console.error(`[Response Simulator] Received response for ${request.type}:`,
JSON.stringify(response, null, 2));
}
/**
* Simulate typing delay
*/
private async simulateTypingDelay(text: string): Promise<void> {
if (!this.config.simulateTyping) return;
// Simulate ~60 WPM typing speed
const wordsPerMinute = 60;
const charactersPerMinute = wordsPerMinute * 5; // Average word length
const millisecondsPerCharacter = 60000 / charactersPerMinute;
const typingTime = text.length * millisecondsPerCharacter;
await this.delay(Math.min(typingTime, 5000)); // Cap at 5 seconds
}
/**
* Create a delay promise
*/
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Generate random completion status based on probabilities
*/
private getRandomCompletionStatus(): 'done' | 'drill-deeper' | 'abort' {
const random = Math.random();
const { done, drillDeeper } = this.config.completionProbability;
if (random < done) return 'done';
if (random < done + drillDeeper) return 'drill-deeper';
return 'abort';
}
/**
* Add variation to mock responses
*/
addResponseVariation(toolType: string, variations: any[]): void {
// Could be extended to support multiple response variations
console.error(`[Response Simulator] Added ${variations.length} variations for ${toolType}`);
}
/**
* Set custom response delay
*/
setResponseDelay(delay: number): void {
this.config.responseDelay = delay;
console.error(`[Response Simulator] Response delay set to ${delay}ms`);
}
/**
* Enable/disable typing simulation
*/
setTypingSimulation(enabled: boolean): void {
this.config.simulateTyping = enabled;
console.error(`[Response Simulator] Typing simulation ${enabled ? 'enabled' : 'disabled'}`);
}
}