mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-14 20:10:36 -07:00
feat: wire up AskUserTool with dialog (#17411)
This commit is contained in:
@@ -87,7 +87,9 @@ describe('AskUserTool', () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toContain('must NOT have fewer than 2 items');
|
||||
expect(result).toContain(
|
||||
"type='choice' requires 'options' array with 2-4 items",
|
||||
);
|
||||
});
|
||||
|
||||
it('should return error if options has more than 4 items', () => {
|
||||
@@ -106,7 +108,7 @@ describe('AskUserTool', () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toContain('must NOT have more than 4 items');
|
||||
expect(result).toContain("'options' array must have at most 4 items");
|
||||
});
|
||||
|
||||
it('should return null for valid params', () => {
|
||||
@@ -124,6 +126,91 @@ describe('AskUserTool', () => {
|
||||
});
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('should return error if choice type has no options', () => {
|
||||
const result = tool.validateToolParams({
|
||||
questions: [
|
||||
{
|
||||
question: 'Pick one?',
|
||||
header: 'Choice',
|
||||
type: QuestionType.CHOICE,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toContain("type='choice' requires 'options'");
|
||||
});
|
||||
|
||||
it('should return error if type is omitted and options missing (defaults to choice)', () => {
|
||||
const result = tool.validateToolParams({
|
||||
questions: [
|
||||
{
|
||||
question: 'Pick one?',
|
||||
header: 'Choice',
|
||||
// type omitted, defaults to 'choice'
|
||||
// options missing
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toContain("type='choice' requires 'options'");
|
||||
});
|
||||
|
||||
it('should accept text type without options', () => {
|
||||
const result = tool.validateToolParams({
|
||||
questions: [
|
||||
{
|
||||
question: 'Enter your name?',
|
||||
header: 'Name',
|
||||
type: QuestionType.TEXT,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('should accept yesno type without options', () => {
|
||||
const result = tool.validateToolParams({
|
||||
questions: [
|
||||
{
|
||||
question: 'Do you want to proceed?',
|
||||
header: 'Confirm',
|
||||
type: QuestionType.YESNO,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('should return error if option has empty label', () => {
|
||||
const result = tool.validateToolParams({
|
||||
questions: [
|
||||
{
|
||||
question: 'Pick one?',
|
||||
header: 'Choice',
|
||||
options: [
|
||||
{ label: '', description: 'Empty label' },
|
||||
{ label: 'B', description: 'Option B' },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toContain("'label' is required");
|
||||
});
|
||||
|
||||
it('should return error if option is missing description', () => {
|
||||
const result = tool.validateToolParams({
|
||||
questions: [
|
||||
{
|
||||
question: 'Pick one?',
|
||||
header: 'Choice',
|
||||
options: [
|
||||
{ label: 'A' } as { label: string; description: string },
|
||||
{ label: 'B', description: 'Option B' },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toContain("must have required property 'description'");
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish ASK_USER_REQUEST and wait for response', async () => {
|
||||
@@ -195,6 +282,46 @@ describe('AskUserTool', () => {
|
||||
expect(JSON.parse(result.llmContent as string)).toEqual({ answers });
|
||||
});
|
||||
|
||||
it('should display message when user submits without answering', async () => {
|
||||
const questions = [
|
||||
{
|
||||
question: 'Which approach?',
|
||||
header: 'Approach',
|
||||
options: [
|
||||
{ label: 'Option A', description: 'First option' },
|
||||
{ label: 'Option B', description: 'Second option' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const invocation = tool.build({ questions });
|
||||
const executePromise = invocation.execute(new AbortController().signal);
|
||||
|
||||
// Get the correlation ID from the published message
|
||||
const publishCall = vi.mocked(mockMessageBus.publish).mock.calls[0][0] as {
|
||||
correlationId: string;
|
||||
};
|
||||
const correlationId = publishCall.correlationId;
|
||||
|
||||
// Simulate response with empty answers
|
||||
const subscribeCall = vi
|
||||
.mocked(mockMessageBus.subscribe)
|
||||
.mock.calls.find((call) => call[0] === MessageBusType.ASK_USER_RESPONSE);
|
||||
const handler = subscribeCall![1];
|
||||
|
||||
handler({
|
||||
type: MessageBusType.ASK_USER_RESPONSE,
|
||||
correlationId,
|
||||
answers: {},
|
||||
});
|
||||
|
||||
const result = await executePromise;
|
||||
expect(result.returnDisplay).toBe(
|
||||
'User submitted without answering questions.',
|
||||
);
|
||||
expect(JSON.parse(result.llmContent as string)).toEqual({ answers: {} });
|
||||
});
|
||||
|
||||
it('should handle cancellation', async () => {
|
||||
const invocation = tool.build({
|
||||
questions: [
|
||||
|
||||
Reference in New Issue
Block a user