aiwg
Version:
Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo
197 lines • 6.7 kB
JavaScript
/**
* MockAgentOrchestrator - Mock Claude Code multi-agent orchestration for isolated testing
*
* Simulates agent execution without real API calls, with support for:
* - Controllable responses and delays
* - Error injection for failure testing
* - Execution history tracking
* - Parallel agent simulation
*
* Satisfies NFR-TEST-004: <10% mismatch with real agent behavior
*/
/**
* Mock orchestrator for multi-agent testing
* Provides realistic simulation of agent execution patterns
*/
export class MockAgentOrchestrator {
registeredAgents = new Map();
executionHistory = [];
globalDelay = 0;
errorInjections = new Map();
delayInjections = new Map();
/**
* Register a mock agent with defined behavior
* @param agentType - Agent identifier (e.g., 'security-architect')
* @param mockBehavior - Configuration for agent behavior
*/
registerAgent(agentType, mockBehavior) {
this.registeredAgents.set(agentType, mockBehavior);
}
/**
* Set global delay applied to all agent executions
* @param ms - Delay in milliseconds
*/
setGlobalDelay(ms) {
if (ms < 0) {
throw new Error('Global delay must be non-negative');
}
this.globalDelay = ms;
}
/**
* Execute a single agent with given prompt
* @param agentType - Type of agent to execute
* @param prompt - Instructions for the agent
* @returns Promise resolving to agent response
* @throws Error if agent not registered or execution fails
*/
async executeAgent(agentType, prompt) {
const startTime = Date.now();
const timestamp = startTime;
// Check for registered agent
const behavior = this.registeredAgents.get(agentType);
if (!behavior) {
throw new Error(`Agent type '${agentType}' is not registered`);
}
// Check for injected error
const injectedError = this.errorInjections.get(agentType);
if (injectedError) {
this.errorInjections.delete(agentType); // One-time injection
const response = {
agentType,
output: '',
executionTime: 0,
error: injectedError
};
this.executionHistory.push({ agentType, prompt, response, timestamp });
throw injectedError;
}
// Check for error rate simulation
if (behavior.errorRate && Math.random() < behavior.errorRate) {
const error = new Error(`Simulated random failure for agent '${agentType}'`);
const response = {
agentType,
output: '',
executionTime: 0,
error
};
this.executionHistory.push({ agentType, prompt, response, timestamp });
throw error;
}
// Calculate total delay
const behaviorDelay = behavior.delay ?? 0;
const injectedDelay = this.delayInjections.get(agentType) ?? 0;
const totalDelay = this.globalDelay + behaviorDelay + injectedDelay;
// Clear one-time delay injection
if (this.delayInjections.has(agentType)) {
this.delayInjections.delete(agentType);
}
// Simulate processing delay
if (totalDelay > 0) {
await this.sleep(totalDelay);
}
// Generate response
const output = behavior.responseGenerator(prompt);
const executionTime = Date.now() - startTime;
const response = {
agentType,
output,
executionTime
};
// Record execution
this.executionHistory.push({ agentType, prompt, response, timestamp });
return response;
}
/**
* Execute multiple agents in parallel
* @param agents - Array of agent requests to execute
* @returns Promise resolving to array of responses (in same order as requests)
*/
async executeParallel(agents) {
const promises = agents.map(({ agentType, prompt }) => this.executeAgent(agentType, prompt)
.catch(error => {
// Return error response instead of throwing
// This allows parallel execution to continue even if one fails
return {
agentType,
output: '',
executionTime: 0,
error: error
};
}));
return Promise.all(promises);
}
/**
* Reset orchestrator state
* Clears execution history, injections, and global delay
* Does NOT clear registered agents
*/
reset() {
this.executionHistory = [];
this.errorInjections.clear();
this.delayInjections.clear();
this.globalDelay = 0;
}
/**
* Get execution history
* @returns Array of all agent executions (chronological order)
*/
getExecutionHistory() {
return [...this.executionHistory]; // Return copy to prevent mutation
}
/**
* Inject one-time error for next execution of specific agent
* @param agentType - Agent that should fail
* @param error - Error to throw on next execution
*/
injectError(agentType, error) {
this.errorInjections.set(agentType, error);
}
/**
* Inject one-time delay for next execution of specific agent
* @param agentType - Agent to delay
* @param ms - Additional delay in milliseconds
*/
injectDelay(agentType, ms) {
if (ms < 0) {
throw new Error('Injected delay must be non-negative');
}
this.delayInjections.set(agentType, ms);
}
/**
* Get list of registered agent types
* @returns Array of registered agent type identifiers
*/
getRegisteredAgents() {
return Array.from(this.registeredAgents.keys());
}
/**
* Check if agent type is registered
* @param agentType - Agent identifier to check
* @returns True if agent is registered
*/
hasAgent(agentType) {
return this.registeredAgents.has(agentType);
}
/**
* Unregister an agent
* @param agentType - Agent to remove
* @returns True if agent was removed, false if not registered
*/
unregisterAgent(agentType) {
return this.registeredAgents.delete(agentType);
}
/**
* Clear all registered agents
*/
clearAgents() {
this.registeredAgents.clear();
}
/**
* Sleep utility for simulating delays
* @param ms - Milliseconds to sleep
*/
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
//# sourceMappingURL=agent-orchestrator.js.map