Skip to content

Commit dcbf57d

Browse files
committed
Chat context API changes
1 parent ee3be3e commit dcbf57d

4 files changed

Lines changed: 186 additions & 37 deletions

File tree

src/@types/vscode.proposed.chatContextProvider.d.ts

Lines changed: 135 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,47 @@ declare module 'vscode' {
1111
export namespace chat {
1212

1313
/**
14-
* Register a chat context provider. Chat context can be provided:
15-
* - For a resource. Make sure to pass a selector that matches the resource you want to provide context for.
16-
* Providers registered without a selector will not be called for resource-based context.
17-
* - Explicitly. These context items are shown as options when the user explicitly attaches context.
14+
* Register a chat workspace context provider. Workspace context is automatically included in all chat requests.
15+
*
16+
* To ensure your extension is activated when chat context is requested, make sure to include the following activations events:
17+
* - If your extension implements `provideWorkspaceChatContext` or `provideChatContextForResource`, find an activation event which is a good signal to activate.
18+
* Ex: `onLanguage:<languageId>`, `onWebviewPanel:<viewType>`, etc.`
19+
* - If your extension implements `provideChatContextExplicit`, your extension will be automatically activated when the user requests explicit context.
20+
*
21+
* @param id Unique identifier for the provider.
22+
* @param provider The chat workspace context provider.
23+
*/
24+
export function registerChatWorkspaceContextProvider(id: string, provider: ChatWorkspaceContextProvider): Disposable;
25+
26+
/**
27+
* Register a chat explicit context provider. Explicit context items are shown as options when the user explicitly attaches context use the "Attache Context" action in the chat input box.
28+
*
29+
* Explicit context providers should also be statically contributed in package.json using the `chatContext` contribution point.
1830
*
1931
* To ensure your extension is activated when chat context is requested, make sure to include the `onChatContextProvider:<id>` activation event in your `package.json`.
2032
*
33+
* @param id Unique identifier for the provider.
34+
* @param provider The chat explicit context provider.
35+
*/
36+
export function registerChatExplicitContextProvider(id: string, provider: ChatExplicitContextProvider): Disposable;
37+
38+
/**
39+
* Register a chat resource context provider. Resource context is provided for a specific resource.
40+
* Make sure to pass a selector that matches the resource you want to provide context for.
41+
*
42+
* To ensure your extension is activated when chat context is requested, make sure to include the `onChatContextProvider:<id>` activation event in your `package.json`.
43+
*
44+
* @param selector Document selector to filter which resources the provider is called for.
45+
* @param id Unique identifier for the provider.
46+
* @param provider The chat resource context provider.
47+
*/
48+
export function registerChatResourceContextProvider(selector: DocumentSelector, id: string, provider: ChatResourceContextProvider): Disposable;
49+
50+
/**
51+
* Register a chat context provider.
52+
*
53+
* @deprecated Use {@link registerChatWorkspaceContextProvider}, {@link registerChatExplicitContextProvider}, or {@link registerChatResourceContextProvider} instead.
54+
*
2155
* @param selector Optional document selector to filter which resources the provider is called for. If omitted, the provider will only be called for explicit context requests.
2256
* @param id Unique identifier for the provider.
2357
* @param provider The chat context provider.
@@ -29,12 +63,21 @@ declare module 'vscode' {
2963
export interface ChatContextItem {
3064
/**
3165
* Icon for the context item.
66+
* - If `icon` is not defined, no icon is shown.
67+
* - If `icon` is defined and is a file or folder icon, the icon is derived from {@link resourceUri} if `resourceUri` is defined.
68+
* - Otherwise, `icon` is used.
3269
*/
33-
icon: ThemeIcon;
70+
icon?: ThemeIcon;
3471
/**
3572
* Human readable label for the context item.
73+
* If not set, the label is derived from {@link resourceUri}.
3674
*/
37-
label: string;
75+
label?: string;
76+
/**
77+
* A resource URI for the context item.
78+
* Used to derive the {@link label} and {@link icon} if they are not set.
79+
*/
80+
resourceUri?: Uri;
3881
/**
3982
* An optional description of the context item, e.g. to describe the item to the language model.
4083
*/
@@ -49,24 +92,34 @@ declare module 'vscode' {
4992
value?: string;
5093
/**
5194
* An optional command that is executed when the context item is clicked.
52-
* The original context item will be passed as an argument to the command.
95+
* The original context item will be passed as the first argument to the command.
5396
*/
5497
command?: Command;
5598
}
5699

57-
export interface ChatContextProvider<T extends ChatContextItem = ChatContextItem> {
100+
export interface ChatWorkspaceContextProvider<T extends ChatContextItem = ChatContextItem> {
58101

59102
/**
60103
* An optional event that should be fired when the workspace chat context has changed.
61104
*/
62105
onDidChangeWorkspaceChatContext?: Event<void>;
63106

64107
/**
65-
* Provide a list of chat context items to be included as workspace context for all chat sessions.
108+
* Provide a list of chat context items to be included as workspace context for all chat requests.
109+
* This should be used very sparingly to avoid providing useless context and to avoid using up the context window.
110+
* A good example use case is to provide information about which branch the user is working on in a source control context.
66111
*
67112
* @param token A cancellation token.
68113
*/
69-
provideWorkspaceChatContext?(token: CancellationToken): ProviderResult<T[]>;
114+
provideWorkspaceChatContext(token: CancellationToken): ProviderResult<T[]>;
115+
116+
/**
117+
* @deprecated
118+
*/
119+
provideChatContext?(token: CancellationToken): ProviderResult<T[]>;
120+
}
121+
122+
export interface ChatExplicitContextProvider<T extends ChatContextItem = ChatContextItem> {
70123

71124
/**
72125
* Provide a list of chat context items that a user can choose from. These context items are shown as options when the user explicitly attaches context.
@@ -75,27 +128,94 @@ declare module 'vscode' {
75128
*
76129
* @param token A cancellation token.
77130
*/
78-
provideChatContextExplicit?(token: CancellationToken): ProviderResult<T[]>;
131+
provideExplicitChatContext(token: CancellationToken): ProviderResult<T[]>;
132+
133+
/**
134+
* @deprecated
135+
*/
136+
provideChatContext?(token: CancellationToken): ProviderResult<T[]>;
137+
138+
/**
139+
* If a chat context item is provided without a `value`, this method is called to resolve the `value` for the item.
140+
*
141+
* @param context The context item to resolve.
142+
* @param token A cancellation token.
143+
*/
144+
resolveExplicitChatContext(context: T, token: CancellationToken): ProviderResult<ChatContextItem>;
145+
146+
/**
147+
* @deprecated
148+
*/
149+
resolveChatContext?(context: T, token: CancellationToken): ProviderResult<ChatContextItem>;
150+
}
151+
152+
export interface ChatResourceContextProvider<T extends ChatContextItem = ChatContextItem> {
79153

80154
/**
81155
* Given a particular resource, provide a chat context item for it. This is used for implicit context (see the settings `chat.implicitContext.enabled` and `chat.implicitContext.suggestedContext`).
82156
* Chat context items can be provided without a `value`, as the `value` can be resolved later using `resolveChatContext`.
83157
* `resolveChatContext` is only called for items that do not have a `value`.
84158
*
85-
* Currently only called when the resource is a webview.
159+
* Called when the resource is a webview or a text editor.
86160
*
87161
* @param options Options include the resource for which to provide context.
88162
* @param token A cancellation token.
89163
*/
90-
provideChatContextForResource?(options: { resource: Uri }, token: CancellationToken): ProviderResult<T | undefined>;
164+
provideResourceChatContext(options: { resource: Uri }, token: CancellationToken): ProviderResult<T | undefined>;
165+
166+
/**
167+
* @deprecated
168+
*/
169+
provideChatContext?(options: { resource: Uri }, token: CancellationToken): ProviderResult<T | undefined>;
91170

92171
/**
93-
* If a chat context item is provided without a `value`, from either of the `provide` methods, this method is called to resolve the `value` for the item.
172+
* If a chat context item is provided without a `value`, this method is called to resolve the `value` for the item.
94173
*
95174
* @param context The context item to resolve.
96175
* @param token A cancellation token.
97176
*/
98-
resolveChatContext(context: T, token: CancellationToken): ProviderResult<ChatContextItem>;
177+
resolveResourceChatContext(context: T, token: CancellationToken): ProviderResult<ChatContextItem>;
178+
179+
/**
180+
* @deprecated
181+
*/
182+
resolveChatContext?(context: T, token: CancellationToken): ProviderResult<ChatContextItem>;
183+
}
184+
185+
/**
186+
* @deprecated Use {@link ChatWorkspaceContextProvider}, {@link ChatExplicitContextProvider}, or {@link ChatResourceContextProvider} instead.
187+
*/
188+
export interface ChatContextProvider<T extends ChatContextItem = ChatContextItem> {
189+
190+
/**
191+
* An optional event that should be fired when the workspace chat context has changed.
192+
* @deprecated Use {@link ChatWorkspaceContextProvider.onDidChangeWorkspaceChatContext} instead.
193+
*/
194+
onDidChangeWorkspaceChatContext?: Event<void>;
195+
196+
/**
197+
* Provide a list of chat context items to be included as workspace context for all chat requests.
198+
* @deprecated Use {@link ChatWorkspaceContextProvider.provideWorkspaceChatContext} instead.
199+
*/
200+
provideWorkspaceChatContext?(token: CancellationToken): ProviderResult<T[]>;
201+
202+
/**
203+
* Provide a list of chat context items that a user can choose from.
204+
* @deprecated Use {@link ChatExplicitContextProvider.provideExplicitChatContext} instead.
205+
*/
206+
provideChatContextExplicit?(token: CancellationToken): ProviderResult<T[]>;
207+
208+
/**
209+
* Given a particular resource, provide a chat context item for it.
210+
* @deprecated Use {@link ChatResourceContextProvider.provideResourceChatContext} instead.
211+
*/
212+
provideChatContextForResource?(options: { resource: Uri }, token: CancellationToken): ProviderResult<T | undefined>;
213+
214+
/**
215+
* If a chat context item is provided without a `value`, this method is called to resolve the `value` for the item.
216+
* @deprecated Use the `resolveChatContext` method on the specific provider type instead.
217+
*/
218+
resolveChatContext?(context: T, token: CancellationToken): ProviderResult<ChatContextItem>;
99219
}
100220

101221
}

src/extension.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { IssueFeatureRegistrar } from './issues/issueFeatureRegistrar';
3434
import { StateManager } from './issues/stateManager';
3535
import { IssueContextProvider } from './lm/issueContextProvider';
3636
import { ChatParticipant, ChatParticipantState } from './lm/participants';
37-
import { PullRequestContextProvider } from './lm/pullRequestContextProvider';
37+
import { PullRequestContextProvider, WorkspaceContextProvider } from './lm/pullRequestContextProvider';
3838
import { registerTools } from './lm/tools/tools';
3939
import { migrate } from './migrations';
4040
import { NotificationsFeatureRegister } from './notifications/notificationsFeatureRegistar';
@@ -269,10 +269,15 @@ async function init(
269269
context.subscriptions.push(issuesFeatures);
270270
await issuesFeatures.initialize();
271271

272-
const pullRequestContextProvider = new PullRequestContextProvider(prsTreeModel, reposManager, git, context);
273-
vscode.chat.registerChatContextProvider({ scheme: 'webview-panel', pattern: '**/webview-PullRequestOverview**' }, 'githubpr', pullRequestContextProvider);
274-
vscode.chat.registerChatContextProvider({ scheme: 'webview-panel', pattern: '**/webview-IssueOverview**' }, 'githubissue', new IssueContextProvider(issueStateManager, reposManager, context));
275-
pullRequestContextProvider.initialize();
272+
const workspaceContextProvider = new WorkspaceContextProvider(reposManager, git);
273+
vscode.chat.registerChatWorkspaceContextProvider('githubpr', workspaceContextProvider);
274+
workspaceContextProvider.initialize();
275+
const pullRequestContextProvider = new PullRequestContextProvider(prsTreeModel, reposManager, context);
276+
vscode.chat.registerChatExplicitContextProvider('githubpr', pullRequestContextProvider);
277+
vscode.chat.registerChatResourceContextProvider({ scheme: 'webview-panel', pattern: '**/webview-PullRequestOverview**' }, 'githubpr', pullRequestContextProvider);
278+
const issueContextProvider = new IssueContextProvider(issueStateManager, reposManager, context);
279+
vscode.chat.registerChatExplicitContextProvider('githubissue', issueContextProvider);
280+
vscode.chat.registerChatResourceContextProvider({ scheme: 'webview-panel', pattern: '**/webview-IssueOverview**' }, 'githubissue', issueContextProvider);
276281

277282
const notificationsFeatures = new NotificationsFeatureRegister(credentialStore, reposManager, telemetry, notificationsManager);
278283
context.subscriptions.push(notificationsFeatures);

src/lm/issueContextProvider.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,35 @@ export namespace IssueChatContextItem {
2222
}
2323
}
2424

25-
export class IssueContextProvider implements vscode.ChatContextProvider {
25+
export class IssueContextProvider implements vscode.ChatExplicitContextProvider<IssueChatContextItem>, vscode.ChatResourceContextProvider<IssueChatContextItem> {
2626
constructor(private readonly _stateManager: StateManager,
2727
private readonly _reposManager: RepositoriesManager,
2828
private readonly _context: vscode.ExtensionContext
2929
) { }
3030

31-
async provideChatContextForResource(_options: { resource: vscode.Uri }, _token: vscode.CancellationToken): Promise<IssueChatContextItem | undefined> {
31+
async provideResourceChatContext(_options: { resource: vscode.Uri; }, _token: vscode.CancellationToken): Promise<IssueChatContextItem | undefined> {
3232
const item = IssueOverviewPanel.currentPanel?.getCurrentItem();
3333
if (item) {
3434
return this._issueToUnresolvedContext(item);
3535
}
3636
}
3737

38-
async resolveChatContext(context: IssueChatContextItem, _token: vscode.CancellationToken): Promise<vscode.ChatContextItem> {
38+
resolveExplicitChatContext(context: IssueChatContextItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.ChatContextItem> {
39+
return this._resolveChatContext(context, token);
40+
}
41+
42+
resolveResourceChatContext(context: IssueChatContextItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.ChatContextItem> {
43+
return this._resolveChatContext(context, token);
44+
}
45+
46+
private async _resolveChatContext(context: IssueChatContextItem, _token: vscode.CancellationToken): Promise<vscode.ChatContextItem> {
3947
context.value = await this._resolvedIssueValue(context.issue);
4048
context.modelDescription = 'All the information about the GitHub issue the user is viewing, including comments.';
4149
context.tooltip = await issueMarkdown(context.issue, this._context, this._reposManager);
4250
return context;
4351
}
4452

45-
async provideChatContextExplicit(_token: vscode.CancellationToken): Promise<IssueChatContextItem[] | undefined> {
53+
async provideExplicitChatContext(_token: vscode.CancellationToken): Promise<IssueChatContextItem[]> {
4654
const contextItems: IssueChatContextItem[] = [];
4755
const seenIssues: Set<string> = new Set();
4856
for (const folderManager of this._reposManager.folderManagers) {

src/lm/pullRequestContextProvider.ts

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ export namespace PRChatContextItem {
2323
}
2424
}
2525

26-
export class PullRequestContextProvider extends Disposable implements vscode.ChatContextProvider {
26+
export class WorkspaceContextProvider extends Disposable implements vscode.ChatWorkspaceContextProvider {
2727
private readonly _onDidChangeWorkspaceChatContext = new vscode.EventEmitter<void>();
2828
readonly onDidChangeWorkspaceChatContext = this._onDidChangeWorkspaceChatContext.event;
2929

30-
constructor(private readonly _prsTreeModel: PrsTreeModel,
30+
constructor(
3131
private readonly _reposManager: RepositoriesManager,
32-
private readonly _git: GitApiImpl,
33-
private readonly _context: vscode.ExtensionContext
32+
private readonly _git: GitApiImpl
3433
) {
3534
super();
3635
}
@@ -90,15 +89,39 @@ Active pull request (may not be the same as open pull request): ${folderManager.
9089
}
9190
return contexts;
9291
}
92+
}
93+
94+
export class PullRequestContextProvider extends Disposable implements vscode.ChatExplicitContextProvider<PRChatContextItem>, vscode.ChatResourceContextProvider<PRChatContextItem> {
95+
constructor(private readonly _prsTreeModel: PrsTreeModel,
96+
private readonly _reposManager: RepositoriesManager,
97+
private readonly _context: vscode.ExtensionContext
98+
) {
99+
super();
100+
}
101+
102+
async provideExplicitChatContext(_token: vscode.CancellationToken): Promise<PRChatContextItem[]> {
103+
const prs = await this._prsTreeModel.getAllPullRequests(this._reposManager.folderManagers[0], false);
104+
return prs.items.map(pr => {
105+
return this._prToUnresolvedContext(pr);
106+
});
107+
}
93108

94-
async provideChatContextForResource(_options: { resource: vscode.Uri }, _token: vscode.CancellationToken): Promise<PRChatContextItem | undefined> {
109+
async provideResourceChatContext(_options: { resource: vscode.Uri; }, _token: vscode.CancellationToken): Promise<PRChatContextItem | undefined> {
95110
const item = PullRequestOverviewPanel.currentPanel?.getCurrentItem();
96111
if (item) {
97112
return this._prToUnresolvedContext(item);
98113
}
99114
}
100115

101-
async resolveChatContext(context: PRChatContextItem, _token: vscode.CancellationToken): Promise<vscode.ChatContextItem> {
116+
async resolveExplicitChatContext(context: PRChatContextItem, token: vscode.CancellationToken): Promise<vscode.ChatContextItem> {
117+
return this._resolveChatContext(context, token);
118+
}
119+
120+
async resolveResourceChatContext(context: PRChatContextItem, token: vscode.CancellationToken): Promise<vscode.ChatContextItem> {
121+
return this._resolveChatContext(context, token);
122+
}
123+
124+
private async _resolveChatContext(context: PRChatContextItem, _token: vscode.CancellationToken): Promise<vscode.ChatContextItem> {
102125
if (!context.pr) {
103126
return context;
104127
}
@@ -108,13 +131,6 @@ Active pull request (may not be the same as open pull request): ${folderManager.
108131
return context;
109132
}
110133

111-
async provideChatContextExplicit(_token: vscode.CancellationToken): Promise<PRChatContextItem[] | undefined> {
112-
const prs = await this._prsTreeModel.getAllPullRequests(this._reposManager.folderManagers[0], false);
113-
return prs.items.map(pr => {
114-
return this._prToUnresolvedContext(pr);
115-
});
116-
}
117-
118134
private _prToUnresolvedContext(pr: PullRequestModel): PRChatContextItem {
119135
return {
120136
icon: new vscode.ThemeIcon('git-pull-request'),

0 commit comments

Comments
 (0)