Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/common/extHostChatContext.ts
4778 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import type * as vscode from 'vscode';
7
import { CancellationToken } from '../../../base/common/cancellation.js';
8
import { URI, UriComponents } from '../../../base/common/uri.js';
9
import { ExtHostChatContextShape, MainContext, MainThreadChatContextShape } from './extHost.protocol.js';
10
import { DocumentSelector } from './extHostTypeConverters.js';
11
import { IExtHostRpcService } from './extHostRpcService.js';
12
import { IChatContextItem } from '../../contrib/chat/common/contextContrib/chatContext.js';
13
import { Disposable, DisposableStore } from '../../../base/common/lifecycle.js';
14
15
export class ExtHostChatContext extends Disposable implements ExtHostChatContextShape {
16
declare _serviceBrand: undefined;
17
18
private _proxy: MainThreadChatContextShape;
19
private _handlePool: number = 0;
20
private _providers: Map<number, { provider: vscode.ChatContextProvider; disposables: DisposableStore }> = new Map();
21
private _itemPool: number = 0;
22
private _items: Map<number, Map<number, vscode.ChatContextItem>> = new Map(); // handle -> itemHandle -> item
23
24
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService,
25
) {
26
super();
27
this._proxy = extHostRpc.getProxy(MainContext.MainThreadChatContext);
28
}
29
30
async $provideChatContext(handle: number, token: CancellationToken): Promise<IChatContextItem[]> {
31
this._items.delete(handle); // clear previous items
32
const provider = this._getProvider(handle);
33
if (!provider.provideChatContextExplicit) {
34
throw new Error('provideChatContext not implemented');
35
}
36
const result = (await provider.provideChatContextExplicit!(token)) ?? [];
37
const items: IChatContextItem[] = [];
38
for (const item of result) {
39
const itemHandle = this._addTrackedItem(handle, item);
40
items.push({
41
handle: itemHandle,
42
icon: item.icon,
43
label: item.label,
44
modelDescription: item.modelDescription,
45
value: item.value
46
});
47
}
48
return items;
49
}
50
51
private _addTrackedItem(handle: number, item: vscode.ChatContextItem): number {
52
const itemHandle = this._itemPool++;
53
if (!this._items.has(handle)) {
54
this._items.set(handle, new Map());
55
}
56
this._items.get(handle)!.set(itemHandle, item);
57
return itemHandle;
58
}
59
60
async $provideChatContextForResource(handle: number, options: { resource: UriComponents; withValue: boolean }, token: CancellationToken): Promise<IChatContextItem | undefined> {
61
const provider = this._getProvider(handle);
62
63
if (!provider.provideChatContextForResource) {
64
throw new Error('provideChatContextForResource not implemented');
65
}
66
67
const result = await provider.provideChatContextForResource({ resource: URI.revive(options.resource) }, token);
68
if (!result) {
69
return undefined;
70
}
71
const itemHandle = this._addTrackedItem(handle, result);
72
73
const item: IChatContextItem | undefined = {
74
handle: itemHandle,
75
icon: result.icon,
76
label: result.label,
77
modelDescription: result.modelDescription,
78
value: options.withValue ? result.value : undefined
79
};
80
if (options.withValue && !item.value && provider.resolveChatContext) {
81
const resolved = await provider.resolveChatContext(result, token);
82
item.value = resolved?.value;
83
}
84
85
return item;
86
}
87
88
private async _doResolve(provider: vscode.ChatContextProvider, context: IChatContextItem, extItem: vscode.ChatContextItem, token: CancellationToken): Promise<IChatContextItem> {
89
const extResult = await provider.resolveChatContext(extItem, token);
90
const result = extResult ?? context;
91
return {
92
handle: context.handle,
93
icon: result.icon,
94
label: result.label,
95
modelDescription: result.modelDescription,
96
value: result.value
97
};
98
}
99
100
async $resolveChatContext(handle: number, context: IChatContextItem, token: CancellationToken): Promise<IChatContextItem> {
101
const provider = this._getProvider(handle);
102
103
if (!provider.resolveChatContext) {
104
throw new Error('resolveChatContext not implemented');
105
}
106
const extItem = this._items.get(handle)?.get(context.handle);
107
if (!extItem) {
108
throw new Error('Chat context item not found');
109
}
110
return this._doResolve(provider, context, extItem, token);
111
}
112
113
registerChatContextProvider(selector: vscode.DocumentSelector | undefined, id: string, provider: vscode.ChatContextProvider): vscode.Disposable {
114
const handle = this._handlePool++;
115
const disposables = new DisposableStore();
116
this._listenForWorkspaceContextChanges(handle, provider, disposables);
117
this._providers.set(handle, { provider, disposables });
118
this._proxy.$registerChatContextProvider(handle, `${id}`, selector ? DocumentSelector.from(selector) : undefined, {}, { supportsResource: !!provider.provideChatContextForResource, supportsResolve: !!provider.resolveChatContext });
119
120
return {
121
dispose: () => {
122
this._providers.delete(handle);
123
this._proxy.$unregisterChatContextProvider(handle);
124
disposables.dispose();
125
}
126
};
127
}
128
129
private _listenForWorkspaceContextChanges(handle: number, provider: vscode.ChatContextProvider, disposables: DisposableStore): void {
130
if (!provider.onDidChangeWorkspaceChatContext || !provider.provideWorkspaceChatContext) {
131
return;
132
}
133
disposables.add(provider.onDidChangeWorkspaceChatContext(async () => {
134
const workspaceContexts = await provider.provideWorkspaceChatContext!(CancellationToken.None);
135
const resolvedContexts: IChatContextItem[] = [];
136
for (const item of workspaceContexts ?? []) {
137
const contextItem: IChatContextItem = {
138
icon: item.icon,
139
label: item.label,
140
modelDescription: item.modelDescription,
141
value: item.value,
142
handle: this._itemPool++
143
};
144
const resolved = await this._doResolve(provider, contextItem, item, CancellationToken.None);
145
resolvedContexts.push(resolved);
146
}
147
148
this._proxy.$updateWorkspaceContextItems(handle, resolvedContexts);
149
}));
150
}
151
152
private _getProvider(handle: number): vscode.ChatContextProvider {
153
if (!this._providers.has(handle)) {
154
throw new Error('Chat context provider not found');
155
}
156
return this._providers.get(handle)!.provider;
157
}
158
159
public override dispose(): void {
160
super.dispose();
161
for (const { disposables } of this._providers.values()) {
162
disposables.dispose();
163
}
164
}
165
}
166
167