Skip to content

Commit f851fe3

Browse files
committed
Moves AI feedback URI state handling to provider
Consolidates storage and context updates for AI feedback responses from the command layer into the provider, improving separation of concerns and maintainability. Ensures feedback state is managed centrally, reducing duplication and potential for inconsistencies. (#4449, #4480)
1 parent 358a7ba commit f851fe3

File tree

3 files changed

+44
-30
lines changed

3 files changed

+44
-30
lines changed

src/commands/aiFeedback.ts

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ import type { AIResultContext } from '../plus/ai/aiProviderService';
66
import { extractAIResultContext } from '../plus/ai/utils/-webview/ai.utils';
77
import type { QuickPickItemOfT } from '../quickpicks/items/common';
88
import { command } from '../system/-webview/command';
9-
import { setContext } from '../system/-webview/context';
10-
import { UriMap } from '../system/-webview/uriMap';
11-
import type { Deferrable } from '../system/function/debounce';
12-
import { debounce } from '../system/function/debounce';
13-
import { filterMap, map } from '../system/iterable';
9+
import { map } from '../system/iterable';
1410
import { Logger } from '../system/logger';
1511
import { ActiveEditorCommand } from './commandBase';
1612
import { getCommandUri } from './commandBase.utils';
@@ -45,32 +41,20 @@ export class AIFeedbackUnhelpfulCommand extends ActiveEditorCommand {
4541

4642
type UnhelpfulResult = { reasons?: AIFeedbackUnhelpfulReasons[]; custom?: string };
4743

48-
const uriResponses = new UriMap<AIFeedbackEvent['sentiment']>();
49-
let _updateContextDebounced: Deferrable<() => void> | undefined;
50-
5144
async function sendFeedback(container: Container, uri: Uri, sentiment: AIFeedbackEvent['sentiment']): Promise<void> {
5245
const context = extractAIResultContext(container, uri);
5346
if (!context) return;
5447

5548
try {
56-
const previous = uriResponses.get(uri);
49+
const previous = container.aiFeedback.getFeedbackResponse(uri);
5750
if (sentiment === previous) return;
5851

5952
let unhelpful: UnhelpfulResult | undefined;
6053
if (sentiment === 'unhelpful') {
6154
unhelpful = await showUnhelpfulFeedbackPicker();
6255
}
6356

64-
uriResponses.set(uri, sentiment);
65-
_updateContextDebounced ??= debounce(() => {
66-
void setContext('gitlens:tabs:ai:helpful', [
67-
...filterMap(uriResponses, ([uri, sentiment]) => (sentiment === 'helpful' ? uri : undefined)),
68-
]);
69-
void setContext('gitlens:tabs:ai:unhelpful', [
70-
...filterMap(uriResponses, ([uri, sentiment]) => (sentiment === 'unhelpful' ? uri : undefined)),
71-
]);
72-
}, 100);
73-
_updateContextDebounced();
57+
container.aiFeedback.setFeedbackResponse(uri, sentiment);
7458

7559
sendFeedbackEvent(container, { source: 'ai:markdown-preview' }, context, sentiment, unhelpful);
7660
} catch (ex) {

src/plus/ai/utils/-webview/ai.utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ export function extractAIResultContext(container: Container, uri: Uri | undefine
298298
// Check for untitled documents with stored changelog feedback context
299299
if (uri?.scheme === 'untitled') {
300300
try {
301-
return container.aiFeedback.getChangelogFeedback(uri.toString());
301+
return container.aiFeedback.getChangelogDocument(uri.toString());
302302
} catch {
303303
return undefined;
304304
}

src/telemetry/aiFeedbackProvider.ts

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import type { Disposable, Uri } from 'vscode';
22
import { workspace } from 'vscode';
3+
import type { AIFeedbackEvent } from '../constants.telemetry';
34
import type { AIResultContext } from '../plus/ai/aiProviderService';
45
import { setContext } from '../system/-webview/context';
6+
import { UriMap } from '../system/-webview/uriMap';
57
import type { Deferrable } from '../system/function/debounce';
68
import { debounce } from '../system/function/debounce';
9+
import { filterMap } from '../system/iterable';
710

811
export class AIFeedbackProvider implements Disposable {
912
constructor() {
@@ -14,20 +17,22 @@ export class AIFeedbackProvider implements Disposable {
1417
}
1518

1619
public addChangelogDocument(uri: Uri, context: AIResultContext): void {
17-
this.setChangelogFeedback(uri.toString(), context);
20+
this.setChangelogDocument(uri.toString(), context);
1821
this.addChangelogUri(uri);
1922
}
2023

2124
private removeChangelogDocument(uri: Uri): void {
22-
this.deleteChangelogFeedback(uri.toString());
25+
this.deleteChangelogDocument(uri.toString());
2326
this.removeChangelogUri(uri);
2427
}
2528

2629
private readonly _disposables: Disposable[] = [];
2730
dispose(): void {
2831
this._disposables.forEach(d => void d.dispose());
29-
this._changelogFeedbacks.clear();
32+
this._uriResponses.clear();
33+
this._changelogDocuments.clear();
3034
this._changelogUris.clear();
35+
this._updateFeedbackContextDebounced = undefined;
3136
this._updateChangelogContextDebounced = undefined;
3237
}
3338

@@ -54,14 +59,39 @@ export class AIFeedbackProvider implements Disposable {
5459
}
5560

5661
// Storage for AI feedback context associated with changelog documents
57-
private readonly _changelogFeedbacks = new Map<string, AIResultContext>();
58-
getChangelogFeedback(documentUri: string): AIResultContext | undefined {
59-
return this._changelogFeedbacks.get(documentUri);
62+
private readonly _changelogDocuments = new Map<string, AIResultContext>();
63+
getChangelogDocument(documentUri: string): AIResultContext | undefined {
64+
return this._changelogDocuments.get(documentUri);
6065
}
61-
private setChangelogFeedback(documentUri: string, context: AIResultContext): void {
62-
this._changelogFeedbacks.set(documentUri, context);
66+
private setChangelogDocument(documentUri: string, context: AIResultContext): void {
67+
this._changelogDocuments.set(documentUri, context);
6368
}
64-
private deleteChangelogFeedback(documentUri: string): void {
65-
this._changelogFeedbacks.delete(documentUri);
69+
private deleteChangelogDocument(documentUri: string): void {
70+
this._changelogDocuments.delete(documentUri);
71+
}
72+
73+
// Storage for AI feedback responses by URI
74+
private readonly _uriResponses = new UriMap<AIFeedbackEvent['sentiment']>();
75+
private _updateFeedbackContextDebounced: Deferrable<() => void> | undefined;
76+
private updateFeedbackContext(): void {
77+
this._updateFeedbackContextDebounced ??= debounce(() => {
78+
void setContext('gitlens:tabs:ai:helpful', [
79+
...filterMap(this._uriResponses, ([uri, sentiment]) => (sentiment === 'helpful' ? uri : undefined)),
80+
]);
81+
void setContext('gitlens:tabs:ai:unhelpful', [
82+
...filterMap(this._uriResponses, ([uri, sentiment]) => (sentiment === 'unhelpful' ? uri : undefined)),
83+
]);
84+
}, 100);
85+
this._updateFeedbackContextDebounced();
86+
}
87+
setFeedbackResponse(uri: Uri, sentiment: AIFeedbackEvent['sentiment']): void {
88+
const previous = this._uriResponses.get(uri);
89+
if (sentiment === previous) return;
90+
91+
this._uriResponses.set(uri, sentiment);
92+
this.updateFeedbackContext();
93+
}
94+
getFeedbackResponse(uri: Uri): AIFeedbackEvent['sentiment'] | undefined {
95+
return this._uriResponses.get(uri);
6696
}
6797
}

0 commit comments

Comments
 (0)