diff --git a/src/agent/manager.ts b/src/agent/manager.ts index 192d59d..8bebaf6 100644 --- a/src/agent/manager.ts +++ b/src/agent/manager.ts @@ -13,7 +13,7 @@ import type { SpawnAgentOptions, AgentResult, AgentStatus, - PendingQuestion, + PendingQuestions, } from './types.js'; import type { AgentRepository } from '../db/repositories/agent-repository.js'; import type { WorktreeManager } from '../git/types.js'; @@ -40,12 +40,12 @@ interface ClaudeCliResult { } /** - * Tracks an active agent subprocess, its result, and any pending question + * Tracks an active agent subprocess, its result, and any pending questions */ interface ActiveAgent { subprocess: ResultPromise; result?: AgentResult; - pendingQuestion?: PendingQuestion; + pendingQuestions?: PendingQuestions; } /** @@ -189,13 +189,11 @@ export class ClaudeAgentManager implements AgentManager { break; } - case 'question': { - // Question path - agent needs input + case 'questions': { + // Questions path - agent needs input (one or more questions) if (active) { - active.pendingQuestion = { - question: agentOutput.question, - options: agentOutput.options, - multiSelect: agentOutput.multiSelect, + active.pendingQuestions = { + questions: agentOutput.questions, }; } await this.repository.updateStatus(agentId, 'waiting_for_input'); @@ -209,9 +207,7 @@ export class ClaudeAgentManager implements AgentManager { name: agent.name, taskId: agent.taskId ?? '', sessionId: cliResult.session_id ?? agent.sessionId ?? '', - question: agentOutput.question, - options: agentOutput.options, - multiSelect: agentOutput.multiSelect, + questions: agentOutput.questions, }, }; this.eventBus.emit(event); @@ -423,11 +419,11 @@ export class ClaudeAgentManager implements AgentManager { } /** - * Get pending question for an agent waiting for input. + * Get pending questions for an agent waiting for input. */ - async getPendingQuestion(agentId: string): Promise { + async getPendingQuestions(agentId: string): Promise { const active = this.activeAgents.get(agentId); - return active?.pendingQuestion ?? null; + return active?.pendingQuestions ?? null; } /** diff --git a/src/agent/mock-manager.test.ts b/src/agent/mock-manager.test.ts index 42eaacb..c52a60b 100644 --- a/src/agent/mock-manager.test.ts +++ b/src/agent/mock-manager.test.ts @@ -211,12 +211,12 @@ describe('MockAgentManager', () => { // spawn() with question scenario // =========================================================================== - describe('spawn with question scenario', () => { + describe('spawn with questions scenario', () => { it('should emit agent:waiting and set status to waiting_for_input', async () => { manager.setScenario('waiting-agent', { - status: 'question', + status: 'questions', delay: 0, - question: 'Should I continue?', + questions: [{ id: 'q1', question: 'Should I continue?' }], }); const agent = await manager.spawn({ @@ -234,7 +234,7 @@ describe('MockAgentManager', () => { // Check event const waitingEvent = eventBus.emittedEvents.find((e) => e.type === 'agent:waiting'); expect(waitingEvent).toBeDefined(); - expect((waitingEvent as any).payload.question).toBe('Should I continue?'); + expect((waitingEvent as any).payload.questions[0].question).toBe('Should I continue?'); }); }); @@ -242,12 +242,12 @@ describe('MockAgentManager', () => { // resume() after waiting_for_input // =========================================================================== - describe('resume after question', () => { + describe('resume after questions', () => { it('should emit agent:resumed and continue with scenario', async () => { manager.setScenario('resume-agent', { - status: 'question', + status: 'questions', delay: 0, - question: 'Need your input', + questions: [{ id: 'q1', question: 'Need your input' }], }); const agent = await manager.spawn({ @@ -504,9 +504,9 @@ describe('MockAgentManager', () => { it('should emit spawned before waiting', async () => { manager.setScenario('wait-order', { - status: 'question', + status: 'questions', delay: 0, - question: 'Test question', + questions: [{ id: 'q1', question: 'Test question' }], }); await manager.spawn({ name: 'wait-order', taskId: 't1', prompt: 'p1' }); await vi.advanceTimersByTimeAsync(0); @@ -599,16 +599,21 @@ describe('MockAgentManager', () => { // Structured question data (new schema tests) // =========================================================================== - describe('structured question data', () => { - it('emits agent:waiting with structured question data', async () => { + describe('structured questions data', () => { + it('emits agent:waiting with structured questions data', async () => { manager.setScenario('test-agent', { - status: 'question', - question: 'Which database?', - options: [ - { label: 'PostgreSQL', description: 'Full-featured' }, - { label: 'SQLite', description: 'Lightweight' }, + status: 'questions', + questions: [ + { + id: 'q1', + question: 'Which database?', + options: [ + { label: 'PostgreSQL', description: 'Full-featured' }, + { label: 'SQLite', description: 'Lightweight' }, + ], + multiSelect: false, + }, ], - multiSelect: false, }); await manager.spawn({ name: 'test-agent', taskId: 'task-1', prompt: 'test' }); @@ -616,52 +621,63 @@ describe('MockAgentManager', () => { const events = eventBus.emittedEvents.filter((e) => e.type === 'agent:waiting'); expect(events.length).toBe(1); - expect((events[0] as any).payload.options).toHaveLength(2); - expect((events[0] as any).payload.options[0].label).toBe('PostgreSQL'); - expect((events[0] as any).payload.multiSelect).toBe(false); + expect((events[0] as any).payload.questions).toHaveLength(1); + expect((events[0] as any).payload.questions[0].options).toHaveLength(2); + expect((events[0] as any).payload.questions[0].options[0].label).toBe('PostgreSQL'); + expect((events[0] as any).payload.questions[0].multiSelect).toBe(false); }); - it('stores pending question for retrieval', async () => { + it('stores pending questions for retrieval', async () => { manager.setScenario('test-agent', { - status: 'question', - question: 'Which database?', - options: [{ label: 'PostgreSQL' }], + status: 'questions', + questions: [ + { + id: 'q1', + question: 'Which database?', + options: [{ label: 'PostgreSQL' }], + }, + ], }); const agent = await manager.spawn({ name: 'test-agent', taskId: 'task-1', prompt: 'test' }); await vi.runAllTimersAsync(); - const pending = await manager.getPendingQuestion(agent.id); - expect(pending?.question).toBe('Which database?'); - expect(pending?.options).toHaveLength(1); - expect(pending?.options?.[0].label).toBe('PostgreSQL'); + const pending = await manager.getPendingQuestions(agent.id); + expect(pending?.questions[0].question).toBe('Which database?'); + expect(pending?.questions[0].options).toHaveLength(1); + expect(pending?.questions[0].options?.[0].label).toBe('PostgreSQL'); }); - it('clears pending question after resume', async () => { + it('clears pending questions after resume', async () => { manager.setScenario('resume-test', { - status: 'question', - question: 'Need your input', - options: [{ label: 'Option A' }, { label: 'Option B' }], + status: 'questions', + questions: [ + { + id: 'q1', + question: 'Need your input', + options: [{ label: 'Option A' }, { label: 'Option B' }], + }, + ], }); const agent = await manager.spawn({ name: 'resume-test', taskId: 'task-1', prompt: 'test' }); await vi.runAllTimersAsync(); - // Verify question is pending - const pendingBefore = await manager.getPendingQuestion(agent.id); + // Verify questions are pending + const pendingBefore = await manager.getPendingQuestions(agent.id); expect(pendingBefore).not.toBeNull(); - expect(pendingBefore?.question).toBe('Need your input'); + expect(pendingBefore?.questions[0].question).toBe('Need your input'); // Resume the agent await manager.resume(agent.id, 'Option A'); - // Pending question should be cleared - const pendingAfter = await manager.getPendingQuestion(agent.id); + // Pending questions should be cleared + const pendingAfter = await manager.getPendingQuestions(agent.id); expect(pendingAfter).toBeNull(); }); - it('returns null for non-existent agent pending question', async () => { - const pending = await manager.getPendingQuestion('non-existent-id'); + it('returns null for non-existent agent pending questions', async () => { + const pending = await manager.getPendingQuestions('non-existent-id'); expect(pending).toBeNull(); }); @@ -669,7 +685,7 @@ describe('MockAgentManager', () => { const agent = await manager.spawn({ name: 'running-agent', taskId: 'task-1', prompt: 'test' }); // Agent is running, not waiting - const pending = await manager.getPendingQuestion(agent.id); + const pending = await manager.getPendingQuestions(agent.id); expect(pending).toBeNull(); }); }); diff --git a/src/agent/mock-manager.ts b/src/agent/mock-manager.ts index 9c95484..0a15c5d 100644 --- a/src/agent/mock-manager.ts +++ b/src/agent/mock-manager.ts @@ -13,7 +13,8 @@ import type { SpawnAgentOptions, AgentResult, AgentStatus, - PendingQuestion, + PendingQuestions, + QuestionItem, } from './types.js'; import type { EventBus, @@ -36,10 +37,8 @@ export type MockAgentScenario = delay?: number; } | { - status: 'question'; - question: string; - options?: Array<{ label: string; description?: string }>; - multiSelect?: boolean; + status: 'questions'; + questions: QuestionItem[]; delay?: number; } | { @@ -56,7 +55,7 @@ interface MockAgentRecord { info: AgentInfo; scenario: MockAgentScenario; result?: AgentResult; - pendingQuestion?: PendingQuestion; + pendingQuestions?: PendingQuestions; completionTimer?: ReturnType; } @@ -239,13 +238,11 @@ export class MockAgentManager implements AgentManager { } break; - case 'question': + case 'questions': record.info.status = 'waiting_for_input'; record.info.updatedAt = new Date(); - record.pendingQuestion = { - question: scenario.question, - options: scenario.options, - multiSelect: scenario.multiSelect, + record.pendingQuestions = { + questions: scenario.questions, }; if (this.eventBus) { @@ -257,9 +254,7 @@ export class MockAgentManager implements AgentManager { name: info.name, taskId: info.taskId, sessionId: info.sessionId ?? '', - question: scenario.question, - options: scenario.options, - multiSelect: scenario.multiSelect, + questions: scenario.questions, }, }; this.eventBus.emit(event); @@ -352,10 +347,10 @@ export class MockAgentManager implements AgentManager { throw new Error(`Agent '${record.info.name}' has no session to resume`); } - // Update status to running, clear pending question + // Update status to running, clear pending questions record.info.status = 'running'; record.info.updatedAt = new Date(); - record.pendingQuestion = undefined; + record.pendingQuestions = undefined; // Emit resumed event if (this.eventBus) { @@ -398,11 +393,11 @@ export class MockAgentManager implements AgentManager { } /** - * Get pending question for an agent waiting for input. + * Get pending questions for an agent waiting for input. */ - async getPendingQuestion(agentId: string): Promise { + async getPendingQuestions(agentId: string): Promise { const record = this.agents.get(agentId); - return record?.pendingQuestion ?? null; + return record?.pendingQuestions ?? null; } /** diff --git a/src/agent/schema.ts b/src/agent/schema.ts index 5632e21..5e76b4f 100644 --- a/src/agent/schema.ts +++ b/src/agent/schema.ts @@ -15,12 +15,22 @@ const optionSchema = z.object({ description: z.string().optional(), }); +/** + * Individual question item with unique ID for answer matching + */ +const questionItemSchema = z.object({ + id: z.string(), + question: z.string(), + options: z.array(optionSchema).optional(), + multiSelect: z.boolean().optional(), +}); + /** * Discriminated union for agent output. * * Agent must return one of: * - done: Task completed successfully - * - question: Agent needs user input to continue + * - questions: Agent needs user input to continue (supports multiple questions) * - unrecoverable_error: Agent hit an error it cannot recover from */ export const agentOutputSchema = z.discriminatedUnion('status', [ @@ -31,12 +41,10 @@ export const agentOutputSchema = z.discriminatedUnion('status', [ filesModified: z.array(z.string()).optional(), }), - // Agent needs user input to continue + // Agent needs user input to continue (one or more questions) z.object({ - status: z.literal('question'), - question: z.string(), - options: z.array(optionSchema).optional(), - multiSelect: z.boolean().optional(), + status: z.literal('questions'), + questions: z.array(questionItemSchema), }), // Agent hit unrecoverable error @@ -66,22 +74,32 @@ export const agentOutputJsonSchema = { }, { properties: { - status: { const: 'question' }, - question: { type: 'string' }, - options: { + status: { const: 'questions' }, + questions: { type: 'array', items: { type: 'object', properties: { - label: { type: 'string' }, - description: { type: 'string' }, + id: { type: 'string' }, + question: { type: 'string' }, + options: { + type: 'array', + items: { + type: 'object', + properties: { + label: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['label'], + }, + }, + multiSelect: { type: 'boolean' }, }, - required: ['label'], + required: ['id', 'question'], }, }, - multiSelect: { type: 'boolean' }, }, - required: ['status', 'question'], + required: ['status', 'questions'], }, { properties: { diff --git a/src/agent/types.ts b/src/agent/types.ts index aa38d42..f0545c2 100644 --- a/src/agent/types.ts +++ b/src/agent/types.ts @@ -56,9 +56,11 @@ export interface AgentResult { } /** - * Pending question when agent is waiting for input + * Individual question item with unique ID for answer matching */ -export interface PendingQuestion { +export interface QuestionItem { + /** Unique identifier for matching answers */ + id: string; /** The question being asked */ question: string; /** Optional predefined options for the question */ @@ -67,6 +69,14 @@ export interface PendingQuestion { multiSelect?: boolean; } +/** + * Pending questions when agent is waiting for input + */ +export interface PendingQuestions { + /** Array of questions the agent is asking */ + questions: QuestionItem[]; +} + /** * AgentManager Port Interface * @@ -147,12 +157,12 @@ export interface AgentManager { getResult(agentId: string): Promise; /** - * Get pending question for an agent waiting for input. + * Get pending questions for an agent waiting for input. * * Only available when agent status is 'waiting_for_input'. * * @param agentId - Agent ID - * @returns Pending question if available, null otherwise + * @returns Pending questions if available, null otherwise */ - getPendingQuestion(agentId: string): Promise; + getPendingQuestions(agentId: string): Promise; } diff --git a/src/dispatch/manager.test.ts b/src/dispatch/manager.test.ts index bd0ed06..14195b2 100644 --- a/src/dispatch/manager.test.ts +++ b/src/dispatch/manager.test.ts @@ -73,7 +73,7 @@ function createMockAgentManager( stop: vi.fn().mockResolvedValue(undefined), resume: vi.fn().mockResolvedValue(undefined), getResult: vi.fn().mockResolvedValue(null), - getPendingQuestion: vi.fn().mockResolvedValue(null), + getPendingQuestions: vi.fn().mockResolvedValue(null), }; } diff --git a/src/events/types.ts b/src/events/types.ts index 1c776d5..b588444 100644 --- a/src/events/types.ts +++ b/src/events/types.ts @@ -183,9 +183,12 @@ export interface AgentWaitingEvent extends DomainEvent { name: string; taskId: string; sessionId: string; - question: string; - options?: Array<{ label: string; description?: string }>; - multiSelect?: boolean; + questions: Array<{ + id: string; + question: string; + options?: Array<{ label: string; description?: string }>; + multiSelect?: boolean; + }>; }; } diff --git a/src/test/e2e/edge-cases.test.ts b/src/test/e2e/edge-cases.test.ts index 0667ca9..8a47859 100644 --- a/src/test/e2e/edge-cases.test.ts +++ b/src/test/e2e/edge-cases.test.ts @@ -151,10 +151,10 @@ describe('E2E Edge Cases', () => { }); await vi.runAllTimersAsync(); - // Set question scenario + // Set questions scenario harness.setAgentScenario(`agent-${taskAId.slice(0, 6)}`, { - status: 'question', - question: 'Which database should I use?', + status: 'questions', + questions: [{ id: 'q1', question: 'Which database should I use?' }], }); await harness.dispatchManager.queue(taskAId); @@ -168,7 +168,7 @@ describe('E2E Edge Cases', () => { expect(waitingEvents.length).toBe(1); const waitingPayload = (waitingEvents[0] as AgentWaitingEvent).payload; expect(waitingPayload.taskId).toBe(taskAId); - expect(waitingPayload.question).toBe('Which database should I use?'); + expect(waitingPayload.questions[0].question).toBe('Which database should I use?'); }); it('resumes agent and completes after resume', async () => { @@ -184,10 +184,10 @@ describe('E2E Edge Cases', () => { }); await vi.runAllTimersAsync(); - // Set question scenario + // Set questions scenario harness.setAgentScenario(`agent-${taskAId.slice(0, 6)}`, { - status: 'question', - question: 'Which database should I use?', + status: 'questions', + questions: [{ id: 'q1', question: 'Which database should I use?' }], }); await harness.dispatchManager.queue(taskAId); @@ -234,10 +234,10 @@ describe('E2E Edge Cases', () => { }); await vi.runAllTimersAsync(); - // Set question scenario + // Set questions scenario harness.setAgentScenario(`agent-${taskAId.slice(0, 6)}`, { - status: 'question', - question: 'Which database should I use?', + status: 'questions', + questions: [{ id: 'q1', question: 'Which database should I use?' }], }); await harness.dispatchManager.queue(taskAId); diff --git a/src/test/e2e/recovery-scenarios.test.ts b/src/test/e2e/recovery-scenarios.test.ts index 7ea0fbc..a19065a 100644 --- a/src/test/e2e/recovery-scenarios.test.ts +++ b/src/test/e2e/recovery-scenarios.test.ts @@ -219,10 +219,16 @@ describe('E2E Recovery Scenarios', () => { }); await vi.runAllTimersAsync(); - // Set question scenario with options - harness.setAgentQuestion(`agent-${taskAId.slice(0, 6)}`, 'Which database should I use?', [ - { label: 'PostgreSQL', description: 'Relational, ACID compliant' }, - { label: 'SQLite', description: 'Lightweight, file-based' }, + // Set questions scenario with options + harness.setAgentQuestions(`agent-${taskAId.slice(0, 6)}`, [ + { + id: 'q1', + question: 'Which database should I use?', + options: [ + { label: 'PostgreSQL', description: 'Relational, ACID compliant' }, + { label: 'SQLite', description: 'Lightweight, file-based' }, + ], + }, ]); // Queue and dispatch @@ -237,7 +243,7 @@ describe('E2E Recovery Scenarios', () => { expect(waitingEvents.length).toBe(1); const waitingPayload = (waitingEvents[0] as AgentWaitingEvent).payload; expect(waitingPayload.taskId).toBe(taskAId); - expect(waitingPayload.question).toBe('Which database should I use?'); + expect(waitingPayload.questions[0].question).toBe('Which database should I use?'); // Clear and resume harness.clearEvents(); @@ -256,7 +262,7 @@ describe('E2E Recovery Scenarios', () => { expect(stoppedPayload.reason).toBe('task_complete'); }); - it('question surfaces as structured PendingQuestion', async () => { + it('questions surface as structured PendingQuestions', async () => { vi.useFakeTimers(); const seeded = await harness.seedFixture(SIMPLE_FIXTURE); const taskAId = seeded.tasks.get('Task A')!; @@ -269,11 +275,17 @@ describe('E2E Recovery Scenarios', () => { }); await vi.runAllTimersAsync(); - // Set question scenario with options - harness.setAgentQuestion(`agent-${taskAId.slice(0, 6)}`, 'Select your framework', [ - { label: 'React' }, - { label: 'Vue' }, - { label: 'Svelte' }, + // Set questions scenario with options + harness.setAgentQuestions(`agent-${taskAId.slice(0, 6)}`, [ + { + id: 'q1', + question: 'Select your framework', + options: [ + { label: 'React' }, + { label: 'Vue' }, + { label: 'Svelte' }, + ], + }, ]); // Queue and dispatch @@ -281,22 +293,22 @@ describe('E2E Recovery Scenarios', () => { const dispatchResult = await harness.dispatchManager.dispatchNext(); await vi.runAllTimersAsync(); - // Verify: agent:waiting event has question + // Verify: agent:waiting event has questions const waitingEvents = harness.getEventsByType('agent:waiting'); expect(waitingEvents.length).toBe(1); const waitingPayload = (waitingEvents[0] as AgentWaitingEvent).payload; - expect(waitingPayload.question).toBe('Select your framework'); - expect(waitingPayload.options).toEqual([ + expect(waitingPayload.questions[0].question).toBe('Select your framework'); + expect(waitingPayload.questions[0].options).toEqual([ { label: 'React' }, { label: 'Vue' }, { label: 'Svelte' }, ]); - // Verify: getPendingQuestion returns structured data - const pendingQuestion = await harness.getPendingQuestion(dispatchResult.agentId!); - expect(pendingQuestion).not.toBeNull(); - expect(pendingQuestion?.question).toBe('Select your framework'); - expect(pendingQuestion?.options).toEqual([ + // Verify: getPendingQuestions returns structured data + const pendingQuestions = await harness.getPendingQuestions(dispatchResult.agentId!); + expect(pendingQuestions).not.toBeNull(); + expect(pendingQuestions?.questions[0].question).toBe('Select your framework'); + expect(pendingQuestions?.questions[0].options).toEqual([ { label: 'React' }, { label: 'Vue' }, { label: 'Svelte' }, @@ -316,8 +328,10 @@ describe('E2E Recovery Scenarios', () => { }); await vi.runAllTimersAsync(); - // Set question scenario - harness.setAgentQuestion(`agent-${taskAId.slice(0, 6)}`, 'Choose database type'); + // Set questions scenario + harness.setAgentQuestions(`agent-${taskAId.slice(0, 6)}`, [ + { id: 'q1', question: 'Choose database type' }, + ]); // Queue and dispatch await harness.dispatchManager.queue(taskAId); @@ -356,8 +370,10 @@ describe('E2E Recovery Scenarios', () => { }); await vi.runAllTimersAsync(); - // Set question scenario - harness.setAgentQuestion(`agent-${taskAId.slice(0, 6)}`, 'API key format?'); + // Set questions scenario + harness.setAgentQuestions(`agent-${taskAId.slice(0, 6)}`, [ + { id: 'q1', question: 'API key format?' }, + ]); // Queue and dispatch await harness.dispatchManager.queue(taskAId); @@ -373,9 +389,9 @@ describe('E2E Recovery Scenarios', () => { agent = await harness.agentManager.get(dispatchResult.agentId!); expect(agent?.status).toBe('waiting_for_input'); - // Verify pending question exists - const pendingQuestion = await harness.getPendingQuestion(dispatchResult.agentId!); - expect(pendingQuestion?.question).toBe('API key format?'); + // Verify pending questions exist + const pendingQuestions = await harness.getPendingQuestions(dispatchResult.agentId!); + expect(pendingQuestions?.questions[0].question).toBe('API key format?'); // Phase 3: Resume await harness.agentManager.resume(dispatchResult.agentId!, 'Bearer token'); @@ -390,9 +406,9 @@ describe('E2E Recovery Scenarios', () => { agent = await harness.agentManager.get(dispatchResult.agentId!); expect(agent?.status).toBe('idle'); - // Verify pending question is cleared after resume - const clearedQuestion = await harness.getPendingQuestion(dispatchResult.agentId!); - expect(clearedQuestion).toBeNull(); + // Verify pending questions is cleared after resume + const clearedQuestions = await harness.getPendingQuestions(dispatchResult.agentId!); + expect(clearedQuestions).toBeNull(); }); }); }); diff --git a/src/test/harness.ts b/src/test/harness.ts index 3151275..3299034 100644 --- a/src/test/harness.ts +++ b/src/test/harness.ts @@ -12,7 +12,7 @@ import type { EventBus, DomainEvent } from '../events/types.js'; import { EventEmitterBus } from '../events/bus.js'; import type { AgentManager } from '../agent/types.js'; import { MockAgentManager, type MockAgentScenario } from '../agent/mock-manager.js'; -import type { PendingQuestion } from '../agent/types.js'; +import type { PendingQuestions, QuestionItem } from '../agent/types.js'; import type { WorktreeManager, Worktree, WorktreeDiff, MergeResult } from '../git/types.js'; import type { DispatchManager } from '../dispatch/types.js'; import { DefaultDispatchManager } from '../dispatch/manager.js'; @@ -197,12 +197,11 @@ export interface TestHarness { setAgentDone(agentName: string, result?: string): void; /** - * Convenience: Set agent to ask a question. + * Convenience: Set agent to ask questions. */ - setAgentQuestion( + setAgentQuestions( agentName: string, - question: string, - options?: Array<{ label: string; description?: string }> + questions: QuestionItem[] ): void; /** @@ -211,9 +210,9 @@ export interface TestHarness { setAgentError(agentName: string, error: string): void; /** - * Get pending question for an agent. + * Get pending questions for an agent. */ - getPendingQuestion(agentId: string): Promise; + getPendingQuestions(agentId: string): Promise; /** * Get events by type. @@ -305,19 +304,18 @@ export function createTestHarness(): TestHarness { agentManager.setScenario(agentName, { status: 'done', result }); }, - setAgentQuestion: ( + setAgentQuestions: ( agentName: string, - question: string, - options?: Array<{ label: string; description?: string }> + questions: QuestionItem[] ) => { - agentManager.setScenario(agentName, { status: 'question', question, options }); + agentManager.setScenario(agentName, { status: 'questions', questions }); }, setAgentError: (agentName: string, error: string) => { agentManager.setScenario(agentName, { status: 'unrecoverable_error', error }); }, - getPendingQuestion: (agentId: string) => agentManager.getPendingQuestion(agentId), + getPendingQuestions: (agentId: string) => agentManager.getPendingQuestions(agentId), getEventsByType: (type: string) => eventBus.getEventsByType(type),