diff --git a/src/agent/mock-manager.ts b/src/agent/mock-manager.ts index 09dccf4..9c95484 100644 --- a/src/agent/mock-manager.ts +++ b/src/agent/mock-manager.ts @@ -26,23 +26,28 @@ import type { /** * Scenario configuration for mock agent behavior. + * Uses discriminated union on status to match agent output schema. */ -export interface MockAgentScenario { - /** How agent completes: 'success' | 'crash' | 'waiting_for_input' */ - outcome: 'success' | 'crash' | 'waiting_for_input'; - /** Delay before completion (ms). Default 0 for synchronous tests. */ - delay?: number; - /** Result message for success/crash */ - message?: string; - /** Files modified (for success) */ - filesModified?: string[]; - /** Question to surface (for waiting_for_input) */ - question?: string; - /** Options for question (for waiting_for_input) */ - options?: Array<{ label: string; description?: string }>; - /** Whether multiple options can be selected (for waiting_for_input) */ - multiSelect?: boolean; -} +export type MockAgentScenario = + | { + status: 'done'; + result?: string; + filesModified?: string[]; + delay?: number; + } + | { + status: 'question'; + question: string; + options?: Array<{ label: string; description?: string }>; + multiSelect?: boolean; + delay?: number; + } + | { + status: 'unrecoverable_error'; + error: string; + attempted?: string; + delay?: number; + }; /** * Internal agent record with scenario and timer tracking. @@ -59,10 +64,10 @@ interface MockAgentRecord { * Default scenario: immediate success with generic message. */ const DEFAULT_SCENARIO: MockAgentScenario = { - outcome: 'success', - delay: 0, - message: 'Task completed successfully', + status: 'done', + result: 'Task completed successfully', filesModified: [], + delay: 0, }; /** @@ -178,7 +183,7 @@ export class MockAgentManager implements AgentManager { } /** - * Complete agent based on scenario outcome. + * Complete agent based on scenario status. */ private completeAgent(agentId: string, scenario: MockAgentScenario): void { const record = this.agents.get(agentId); @@ -186,11 +191,11 @@ export class MockAgentManager implements AgentManager { const { info } = record; - switch (scenario.outcome) { - case 'success': + switch (scenario.status) { + case 'done': record.result = { success: true, - message: scenario.message ?? 'Task completed successfully', + message: scenario.result ?? 'Task completed successfully', filesModified: scenario.filesModified, }; record.info.status = 'idle'; @@ -211,10 +216,10 @@ export class MockAgentManager implements AgentManager { } break; - case 'crash': + case 'unrecoverable_error': record.result = { success: false, - message: scenario.message ?? 'Agent crashed', + message: scenario.error, }; record.info.status = 'crashed'; record.info.updatedAt = new Date(); @@ -227,18 +232,18 @@ export class MockAgentManager implements AgentManager { agentId, name: info.name, taskId: info.taskId, - error: scenario.message ?? 'Agent crashed', + error: scenario.error, }, }; this.eventBus.emit(event); } break; - case 'waiting_for_input': + case 'question': record.info.status = 'waiting_for_input'; record.info.updatedAt = new Date(); record.pendingQuestion = { - question: scenario.question ?? 'User input required', + question: scenario.question, options: scenario.options, multiSelect: scenario.multiSelect, }; @@ -252,7 +257,7 @@ export class MockAgentManager implements AgentManager { name: info.name, taskId: info.taskId, sessionId: info.sessionId ?? '', - question: scenario.question ?? 'User input required', + question: scenario.question, options: scenario.options, multiSelect: scenario.multiSelect, }, @@ -369,11 +374,14 @@ export class MockAgentManager implements AgentManager { // Re-run scenario (after resume, typically completes successfully) // For testing, we use a new scenario that defaults to success + // Extract filesModified from original scenario if it was a 'done' type + const originalFilesModified = + record.scenario.status === 'done' ? record.scenario.filesModified : undefined; const resumeScenario: MockAgentScenario = { - outcome: 'success', + status: 'done', delay: record.scenario.delay ?? 0, - message: 'Resumed and completed successfully', - filesModified: record.scenario.filesModified, + result: 'Resumed and completed successfully', + filesModified: originalFilesModified, }; this.scheduleCompletion(agentId, resumeScenario);