Skip to content

Commit 72a55b6

Browse files
authored
Label search polish (#6411)
1 parent ccfc63c commit 72a55b6

1 file changed

Lines changed: 24 additions & 19 deletions

File tree

src/lm/tools/searchTools.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ You are an expert on choosing search keywords based on a natural language search
123123
- Respond with a space-separated list of labels: Examples: 'bug polish', 'accessibility "feature accessibility"'
124124
- Only choose labels that you're sure are relevant. Having no labels is preferable than lables that aren't relevant.
125125
- Don't choose labels that the user has explicitly excluded.
126-
- Respond with labels chosen from these options:
127-
${labels.map(label => label.name).filter(label => !label.includes('required') && !label.includes('search') && !label.includes('question') && !label.includes('find')).join(', ')}
126+
- Respond with label names chosen from this JSON array of options:
127+
${JSON.stringify(labels.filter(label => !label.name.includes('required') && !label.name.includes('search') && !label.name.includes('question') && !label.name.includes('find')).map(label => ({ name: label.name, description: label.description })))}
128128
`;
129129
}
130130

@@ -138,11 +138,12 @@ You are getting ready to make a GitHub search query. Given a natural language qu
138138
- Respond with only your chosen key word.
139139
- It's better to return no keywords than to return irrelevant keywords.
140140
- If an issue is provided, choose a keyword that names the feature or bug that the issue is about.
141+
- Don't include key words or concepts that are already covered by labels.
141142
`;
142143
}
143144

144-
private freeFormUserPrompt(originalUserPrompt: string): string {
145-
return `The best search keywords in "${originalUserPrompt}" are:`;
145+
private freeFormUserPrompt(labels: string[], originalUserPrompt: string): string {
146+
return `I've already included the following labels: [${labels.join(', ')}]. The best search keywords in "${originalUserPrompt}" are:`;
146147
}
147148

148149
private labelsUserPrompt(originalUserPrompt: string): string {
@@ -221,7 +222,7 @@ You are getting ready to make a GitHub search query. Given a natural language qu
221222
// Currently, we only allow the free form to return one keyword
222223
freeForm = freeForm.trim();
223224
// useless strings to search for
224-
if (freeForm.includes('issue') || freeForm.match(MATCH_UNQUOTED_SPACES)) {
225+
if (freeForm.includes('issue') || freeForm.match(MATCH_UNQUOTED_SPACES) || freeForm.toLowerCase() === 'none') {
225226
return '';
226227
}
227228
if (baseQuery.includes(freeForm)) {
@@ -236,7 +237,7 @@ You are getting ready to make a GitHub search query. Given a natural language qu
236237
return freeForm;
237238
}
238239

239-
private validateQuery(query: string, labelsList: string, allLabels: ILabel[], freeForm: string) {
240+
private validateQuery(query: string, labels: string[], freeForm: string) {
240241
let reformedQuery = '';
241242
const queryParts = query.split(MATCH_UNQUOTED_SPACES);
242243
// Only keep property:value pairs and '-', no reform allowed here.
@@ -255,23 +256,26 @@ You are getting ready to make a GitHub search query. Given a natural language qu
255256
if (!this.validateSpecificQueryPart(label, value)) {
256257
continue;
257258
}
259+
if (label === 'no' && value === 'label' && labels.length > 0) {
260+
// special case for no:label as we shouldn't have both no:label and label:label
261+
continue;
262+
}
258263
}
259264
reformedQuery = `${reformedQuery} ${part}`;
260265
}
261266

262-
const validLabels = this.validateLabelsList(labelsList, allLabels);
263-
const validFreeForm = this.validateFreeForm(reformedQuery, validLabels, freeForm);
267+
const validFreeForm = this.validateFreeForm(reformedQuery, labels, freeForm);
264268

265-
reformedQuery = `${reformedQuery} ${validLabels.map(label => `label:${label}`).join(' ')} ${validFreeForm}`;
269+
reformedQuery = `${reformedQuery} ${labels.map(label => `label:${label}`).join(' ')} ${validFreeForm}`;
266270
return reformedQuery.trim();
267271
}
268272

269-
private postProcess(queryPart: string, freeForm: string, labelsList: string, allLabels: ILabel[]): ConvertToQuerySyntaxResult | undefined {
273+
private postProcess(queryPart: string, freeForm: string, labels: string[]): ConvertToQuerySyntaxResult | undefined {
270274
const query = this.findQuery(queryPart);
271275
if (!query) {
272276
return;
273277
}
274-
const fixedLabels = this.validateQuery(query, labelsList, allLabels, freeForm);
278+
const fixedLabels = this.validateQuery(query, labels, freeForm);
275279
const fixedRepo = this.fixRepo(fixedLabels);
276280
return fixedRepo;
277281
}
@@ -335,9 +339,9 @@ You are getting ready to make a GitHub search query. Given a natural language qu
335339
return concatAsyncIterable(response.text);
336340
}
337341

338-
private async generateFreeFormQuery(folderManager: FolderRepositoryManager, chatOptions: vscode.LanguageModelChatRequestOptions, model: vscode.LanguageModelChat, naturalLanguageString: string, token: vscode.CancellationToken): Promise<string> {
342+
private async generateFreeFormQuery(folderManager: FolderRepositoryManager, chatOptions: vscode.LanguageModelChatRequestOptions, model: vscode.LanguageModelChat, naturalLanguageString: string, labels: string[], token: vscode.CancellationToken): Promise<string> {
339343
const messages = [vscode.LanguageModelChatMessage.Assistant(this.freeFormAssistantPrompt())];
340-
messages.push(vscode.LanguageModelChatMessage.User(this.freeFormUserPrompt(naturalLanguageString)));
344+
messages.push(vscode.LanguageModelChatMessage.User(this.freeFormUserPrompt(labels, naturalLanguageString)));
341345
const response = await model.sendRequest(messages, chatOptions, token);
342346
return concatAsyncIterable(response.text);
343347
}
@@ -359,7 +363,7 @@ You are getting ready to make a GitHub search query. Given a natural language qu
359363
const { owner, name, folderManager } = await this.getRepoInfo({ owner: options.parameters.repo?.owner, name: options.parameters.repo?.name });
360364
const firstUserMessage = `${this.chatParticipantState.firstUserMessage?.value}, ${options.parameters.naturalLanguageString}`;
361365

362-
const labels = await folderManager.getLabels(undefined, { owner, repo: name });
366+
const allLabels = await folderManager.getLabels(undefined, { owner, repo: name });
363367

364368
const models = await vscode.lm.selectChatModels({
365369
vendor: 'copilot',
@@ -369,9 +373,10 @@ You are getting ready to make a GitHub search query. Given a natural language qu
369373
const chatOptions: vscode.LanguageModelChatRequestOptions = {
370374
justification: 'Answering user questions pertaining to GitHub.'
371375
};
372-
const [query, freeForm, labelsList] = await Promise.all([this.generateQuery(folderManager, chatOptions, model, firstUserMessage, token), this.generateFreeFormQuery(folderManager, chatOptions, model, firstUserMessage, token), this.generateLabelQuery(folderManager, labels, chatOptions, model, firstUserMessage, token)]);
373-
374-
const result = this.postProcess(query, freeForm, labelsList, labels);
376+
const [query, labelsList] = await Promise.all([this.generateQuery(folderManager, chatOptions, model, firstUserMessage, token), this.generateLabelQuery(folderManager, allLabels, chatOptions, model, firstUserMessage, token)]);
377+
const validatedLabels = this.validateLabelsList(labelsList, allLabels);
378+
const freeForm = await this.generateFreeFormQuery(folderManager, chatOptions, model, firstUserMessage, validatedLabels, token);
379+
const result = this.postProcess(query, freeForm, validatedLabels);
375380
if (!result) {
376381
throw new Error('Unable to form a query.');
377382
}
@@ -447,7 +452,7 @@ export class SearchTool extends RepoToolBase<SearchToolParameters> {
447452
if (!searchResult) {
448453
throw new Error(`No issues found for ${parameterQuery}. Make sure the query is valid.`);
449454
}
450-
const cutoff = 20;
455+
const cutoff = 30;
451456
const result: SearchToolResult = {
452457
arrayOfIssues: searchResult.items.slice(0, cutoff).map(i => {
453458
const item = i.item;
@@ -471,6 +476,6 @@ export class SearchTool extends RepoToolBase<SearchToolParameters> {
471476
Logger.debug(`Found ${result.totalIssues} issues, first issue ${result.arrayOfIssues[0]?.number}.`, SearchTool.ID);
472477

473478
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(JSON.stringify(result)),
474-
new vscode.LanguageModelTextPart(`Above are the issues I found for the query ${parameterQuery} in json format. You can pass these to a tool that can display them.`)]);
479+
new vscode.LanguageModelTextPart(`Above are the issues I found for the query ${parameterQuery} in json format. You can pass these to a tool that can display them, or you can reason over the issues to answer a question.`)]);
475480
}
476481
}

0 commit comments

Comments
 (0)