61
return value;
62
}
64
>
export interface IQuestionOption {
65
>
readonly label: string;
66
>
readonly description?: string;
67
>
readonly recommended?: boolean;
68
>
}
69
>
70
>
export interface IQuestion {
71
>
readonly header: string;
72
>
readonly question: string;
73
>
readonly message?: string;
74
>
readonly multiSelect?: boolean;
75
>
readonly options?: IQuestionOption[];
76
>
readonly allowFreeformInput?: boolean;
77
>
}
78
>
79
>
export interface IAskQuestionsParams {
80
>
readonly questions: IQuestion[];
81
>
}
82
>
83
>
export interface IQuestionAnswer {
84
>
readonly selected: string[];
85
>
readonly freeText: string | null;
86
>
readonly skipped: boolean;
87
>
}
88
>
89
>
export interface IAnswerResult {
90
>
readonly answers: Record<string, IQuestionAnswer>;
91
>
}
92
>
93
>
export function createAskQuestionsToolData(): IToolData {
94
>
const questionSchema: IJSONSchema & { properties: IJSONSchemaMap } = {
95
>
type: 'object',
96
>
properties: {
97
>
header: {
98
>
type: 'string',
99
>
description: `Short identifier for the question. Must be unique so answers can be mapped back to the question. Maximum ${SoftLimits.header} characters.`,
100
>
maxLength: SoftLimits.header
101
>
},
102
>
question: {
103
>
type: 'string',
104
>
description: `The question text to display to the user. Keep it concise, ideally one sentence. Maximum ${SoftLimits.question} characters.`,
105
>
maxLength: SoftLimits.question
106
>
},
107
>
multiSelect: {
108
>
type: 'boolean',
109
>
description: 'Allow selecting multiple options when options are provided.'
110
>
},
111
>
allowFreeformInput: {
112
>
type: 'boolean',
113
>
description: 'Allow freeform text answers in addition to option selection. Defaults to true; set to false to restrict to predefined options only.'
114
>
},
115
>
message: {
116
>
type: 'string',
117
>
description: 'Optional markdown message to display below the question text, providing additional context or details.'
118
>
},
119
>
options: {
120
>
type: 'array',
121
>
description: 'Optional list of selectable answers. If omitted, the question is free text.',
122
>
items: {
123
>
type: 'object',
124
>
properties: {
125
>
label: {
126
>
type: 'string',
127
>
description: 'Display label and value for the option.'
128
>
},
129
>
description: {
130
>
type: 'string',
131
>
description: 'Optional secondary text shown with the option.'
132
>
},
133
>
recommended: {
134
>
type: 'boolean',
135
>
description: 'Mark this option as the recommended default.'
136
>
}
137
>
},
138
>
required: ['label']
139
>
}
140
>
}
141
>
},
142
>
required: ['header', 'question']
143
>
};
144
>
145
>
const inputSchema: IJSONSchema & { properties: IJSONSchemaMap } = {
146
>
type: 'object',
147
>
properties: {
148
>
questions: {
149
>
type: 'array',
150
>
description: 'List of questions to ask the user. Order is preserved.',
151
>
items: questionSchema,
152
>
minItems: 1
153
>
}
154
>
},
155
>
required: ['questions']
156
>
};
157
>
158
>
return {
159
>
id: AskQuestionsToolId,
160
>
toolReferenceName: 'askQuestions',
161
>
legacyToolReferenceFullNames: [AskQuestionsToolId, 'vscode/askQuestions'],
162
>
canBeReferencedInPrompt: false,
163
>
icon: ThemeIcon.fromId(Codicon.question.id),
164
>
displayName: localize('tool.askQuestions.displayName', 'Ask Clarifying Questions'),
165
>
userDescription: localize('tool.askQuestions.userDescription', 'Ask structured clarifying questions using single select, multi-select, or freeform inputs to collect task requirements before proceeding.'),
166
>
modelDescription: 'Use this tool to ask the user a small number of clarifying questions before proceeding. Provide the questions array with concise headers and prompts. Use options for fixed choices, set multiSelect when multiple selections are allowed. Users can always provide a freeform text answer alongside options unless you set allowFreeformInput to false.',
167
>
source: ToolDataSource.Internal,
168
>
inputSchema
169
>
};
170
>
}
171
>
172
>
export const AskQuestionsToolData: IToolData = createAskQuestionsToolData();
173
>
174
>
export class AskQuestionsTool extends Disposable implements IToolImpl {
175
>
176
>
constructor(
177
>
@IChatService private readonly chatService: IChatService,
178
>
@ITelemetryService private readonly telemetryService: ITelemetryService,
179
>
@ILogService private readonly logService: ILogService,
180
>
@IConfigurationService private readonly configService: IConfigurationService,
181
>
) {
182
>
super();
183
>
}
184
>
185
>
async invoke(invocation: IToolInvocation, _countTokens: CountTokensCallback, progress: ToolProgress, token: CancellationToken): Promise<IToolResult> {
186
const stopWatch = StopWatch.create(true);
187
const parameters = invocation.parameters as IAskQuestionsParams;