3
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
- import { Emitter , Event } from 'vs/base/common/event' ;
7
- import { Disposable , DisposableStore , IDisposable } from 'vs/base/common/lifecycle' ;
6
+ import { Emitter } from 'vs/base/common/event' ;
7
+ import { Disposable } from 'vs/base/common/lifecycle' ;
8
8
import { createDecorator } from 'vs/platform/instantiation/common/instantiation' ;
9
9
import { IStorageService , StorageScope , StorageTarget } from 'vs/platform/storage/common/storage' ;
10
- import { ExtensionIdentifier , IExtensionManifest } from 'vs/platform/extensions/common/extensions' ;
11
- import { Extensions , IExtensionFeatureMarkdownAndTableRenderer , IExtensionFeaturesRegistry , IRenderedData , ITableData } from 'vs/workbench/services/extensionManagement/common/extensionFeatures' ;
12
- import { ILanguageModelsService } from 'vs/workbench/contrib/chat/common/languageModels' ;
13
- import { getExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil' ;
14
- import { IMarkdownString , MarkdownString } from 'vs/base/common/htmlContent' ;
10
+ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions' ;
11
+ import { Extensions , IExtensionFeaturesManagementService , IExtensionFeaturesRegistry } from 'vs/workbench/services/extensionManagement/common/extensionFeatures' ;
15
12
import { Registry } from 'vs/platform/registry/common/platform' ;
16
13
import { localize } from 'vs/nls' ;
17
- import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors' ;
18
- import { ChatAgentLocation , IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents' ;
19
-
20
- export interface ILanguageModelStats {
21
- readonly identifier : string ;
22
- readonly extensions : {
23
- readonly extensionId : string ;
24
- readonly requestCount : number ;
25
- readonly tokenCount : number ;
26
- readonly sessionRequestCount : number ;
27
- readonly sessionTokenCount : number ;
28
- readonly participants : {
29
- readonly id : string ;
30
- readonly requestCount : number ;
31
- readonly tokenCount : number ;
32
- readonly sessionRequestCount : number ;
33
- readonly sessionTokenCount : number ;
34
- } [ ] ;
35
- } [ ] ;
36
- }
37
14
38
15
export const ILanguageModelStatsService = createDecorator < ILanguageModelStatsService > ( 'ILanguageModelStatsService' ) ;
39
16
40
17
export interface ILanguageModelStatsService {
41
-
42
18
readonly _serviceBrand : undefined ;
43
19
44
- readonly onDidChangeLanguageMoelStats : Event < string > ;
45
-
46
- hasAccessedModel ( extensionId : string , model : string ) : boolean ;
47
-
48
20
update ( model : string , extensionId : ExtensionIdentifier , agent : string | undefined , tokenCount : number | undefined ) : Promise < void > ;
49
- fetch ( model : string ) : Promise < ILanguageModelStats > ;
50
-
51
21
}
52
22
53
23
interface LanguageModelStats {
@@ -76,6 +46,7 @@ export class LanguageModelStatsService extends Disposable implements ILanguageMo
76
46
private readonly sessionStats = new Map < string , LanguageModelStats > ( ) ;
77
47
78
48
constructor (
49
+ @IExtensionFeaturesManagementService private readonly extensionFeaturesManagementService : IExtensionFeaturesManagementService ,
79
50
@IStorageService private readonly _storageService : IStorageService ,
80
51
) {
81
52
super ( ) ;
@@ -91,35 +62,9 @@ export class LanguageModelStatsService extends Disposable implements ILanguageMo
91
62
return this . getAccessExtensions ( model ) . includes ( extensionId . toLowerCase ( ) ) ;
92
63
}
93
64
94
- async fetch ( model : string ) : Promise < ILanguageModelStats > {
95
- const globalStats = await this . read ( model ) ;
96
- const sessionStats = this . sessionStats . get ( model ) ?? { extensions : [ ] } ;
97
- return {
98
- identifier : model ,
99
- extensions : globalStats . extensions . map ( extension => {
100
- const sessionExtension = sessionStats . extensions . find ( e => e . extensionId === extension . extensionId ) ;
101
- return {
102
- extensionId : extension . extensionId ,
103
- requestCount : extension . requestCount ,
104
- tokenCount : extension . tokenCount ,
105
- sessionRequestCount : sessionExtension ?. requestCount ?? 0 ,
106
- sessionTokenCount : sessionExtension ?. tokenCount ?? 0 ,
107
- participants : extension . participants . map ( participant => {
108
- const sessionParticipant = sessionExtension ?. participants . find ( p => p . id === participant . id ) ;
109
- return {
110
- id : participant . id ,
111
- requestCount : participant . requestCount ,
112
- tokenCount : participant . tokenCount ,
113
- sessionRequestCount : sessionParticipant ?. requestCount ?? 0 ,
114
- sessionTokenCount : sessionParticipant ?. tokenCount ?? 0
115
- } ;
116
- } )
117
- } ;
118
- } )
119
- } ;
120
- }
121
-
122
65
async update ( model : string , extensionId : ExtensionIdentifier , agent : string | undefined , tokenCount : number | undefined ) : Promise < void > {
66
+ await this . extensionFeaturesManagementService . getAccess ( extensionId , 'languageModels' ) ;
67
+
123
68
// update model access
124
69
this . addAccess ( model , extensionId . value ) ;
125
70
@@ -215,172 +160,11 @@ export class LanguageModelStatsService extends Disposable implements ILanguageMo
215
160
}
216
161
}
217
162
218
- interface Stats {
219
- requestCount : number ;
220
- tokenCount : number ;
221
- sessionRequestCount : number ;
222
- sessionTokenCount : number ;
223
- }
224
-
225
- interface ExtensionLanguageModelStats extends Stats {
226
- languageModelId : string ;
227
- other : Stats ;
228
- participants : Array < Stats & { name : string } > ;
229
- }
230
-
231
- class LanguageModelFeatureRenderer extends Disposable implements IExtensionFeatureMarkdownAndTableRenderer {
232
-
233
- readonly type = 'markdown+table' ;
234
-
235
- constructor (
236
- @ILanguageModelsService private readonly _languageModelsService : ILanguageModelsService ,
237
- @ILanguageModelStatsService private readonly _languageModelStatsService : ILanguageModelStatsService ,
238
- @IChatAgentService private readonly _chatAgentService : IChatAgentService ,
239
- ) {
240
- super ( ) ;
241
- }
242
-
243
- shouldRender ( manifest : IExtensionManifest ) : boolean {
244
- if ( ! ! manifest . contributes ?. chatParticipants ?. length ) {
245
- return true ;
246
- }
247
- const extensionId = getExtensionId ( manifest . publisher , manifest . name ) ;
248
- if ( this . _languageModelsService . getLanguageModelIds ( ) . some ( id =>
249
- this . _languageModelStatsService . hasAccessedModel ( extensionId , id )
250
- || ExtensionIdentifier . equals ( this . _languageModelsService . lookupLanguageModel ( id ) ?. extension , extensionId ) ) ) {
251
- return true ;
252
- }
253
- return false ;
254
- }
255
-
256
- render ( manifest : IExtensionManifest ) : IRenderedData < Array < IMarkdownString | ITableData > > {
257
- const disposables = new DisposableStore ( ) ;
258
- const extensionId = getExtensionId ( manifest . publisher , manifest . name ) ;
259
- const emitter = disposables . add ( new Emitter < Array < IMarkdownString | ITableData > > ( ) ) ;
260
-
261
- this . fetchAllLanguageModelStats ( extensionId ) . then ( ( { data, onDidChange, disposable } ) => {
262
- disposables . add ( disposable ) ;
263
- const renderData = ( languageModelStats : ExtensionLanguageModelStats [ ] ) => {
264
- const data : Array < IMarkdownString | ITableData > = [ ] ;
265
- for ( const stats of languageModelStats ) {
266
- if ( stats . requestCount > 0 ) {
267
- const languageModelTitle = new MarkdownString ( ) ;
268
- languageModelTitle . appendMarkdown ( ` ` ) ;
269
- languageModelTitle . appendMarkdown ( `\n\n### ${ stats . languageModelId } \n---\n\n` ) ;
270
- data . push ( languageModelTitle ) ;
271
- const tableData : ITableData = {
272
- headers : [ localize ( 'participant' , "Participant" ) , localize ( 'requests' , "Requests" ) , localize ( 'tokens' , "Tokens" ) , localize ( 'requests session' , "Requests (Session)" ) , localize ( 'tokens session' , "Tokens (Session)" ) ] ,
273
- rows : [
274
- ...stats . participants . map ( participant => [ participant . name , `${ participant . requestCount } ` , `${ participant . tokenCount } ` , `${ participant . sessionRequestCount } ` , `${ participant . sessionTokenCount } ` ] ) ,
275
- stats . other . requestCount > 0 ? [ stats . participants . length ? 'Other' : '' , `${ stats . other . requestCount } ` , `${ stats . other . tokenCount } ` , `${ stats . other . sessionRequestCount } ` , `${ stats . other . sessionTokenCount } ` ] : [ ] ,
276
- stats . participants . length ? [ 'Total' , `${ stats . requestCount } ` , `${ stats . tokenCount } ` , `${ stats . sessionRequestCount } ` , `${ stats . sessionTokenCount } ` ] : [ ] ,
277
- ]
278
- } ;
279
- data . push ( tableData ) ;
280
- }
281
- }
282
- return data ;
283
- } ;
284
- emitter . fire ( renderData ( data ) ) ;
285
- disposables . add ( onDidChange ( data => emitter . fire ( renderData ( data ) ) ) ) ;
286
- } ) ;
287
-
288
- const data : Array < IMarkdownString | ITableData > = [ ] ;
289
- data . push ( new MarkdownString ( ) . appendMarkdown ( `Fetching...` ) ) ;
290
-
291
- return {
292
- data,
293
- onDidChange : emitter . event ,
294
- dispose : ( ) => {
295
- disposables . dispose ( ) ;
296
- }
297
- } ;
298
- }
299
-
300
- private async fetchAllLanguageModelStats ( extensionId : string ) : Promise < { data : ExtensionLanguageModelStats [ ] ; onDidChange : Event < ExtensionLanguageModelStats [ ] > ; disposable : IDisposable } > {
301
- const disposables = new DisposableStore ( ) ;
302
- const data : ExtensionLanguageModelStats [ ] = [ ] ;
303
- const emitter = disposables . add ( new Emitter < ExtensionLanguageModelStats [ ] > ( ) ) ;
304
-
305
- const models = this . _languageModelsService . getLanguageModelIds ( ) ;
306
- for ( const model of models ) {
307
- data . push ( await this . fetchLanguageModelStats ( extensionId , model ) ) ;
308
- }
309
-
310
- disposables . add ( this . _languageModelStatsService . onDidChangeLanguageMoelStats ( model => {
311
- this . fetchLanguageModelStats ( extensionId , model ) . then ( stats => {
312
- const index = data . findIndex ( d => d . languageModelId === model ) ;
313
- if ( index !== - 1 ) {
314
- data [ index ] = stats ;
315
- } else {
316
- data . push ( stats ) ;
317
- }
318
- emitter . fire ( data ) ;
319
- } ) ;
320
- } ) ) ;
321
-
322
- return {
323
- data,
324
- onDidChange : emitter . event ,
325
- disposable : disposables
326
- } ;
327
- }
328
-
329
- private async fetchLanguageModelStats ( extensionId : string , languageModel : string ) : Promise < ExtensionLanguageModelStats > {
330
- const result : ExtensionLanguageModelStats = {
331
- languageModelId : languageModel ,
332
- requestCount : 0 ,
333
- tokenCount : 0 ,
334
- sessionRequestCount : 0 ,
335
- sessionTokenCount : 0 ,
336
- other : {
337
- requestCount : 0 ,
338
- tokenCount : 0 ,
339
- sessionRequestCount : 0 ,
340
- sessionTokenCount : 0 ,
341
- } ,
342
- participants : [ ]
343
- } ;
344
- const stats = await this . _languageModelStatsService . fetch ( languageModel ) ;
345
- const extensionStats = stats ?. extensions . find ( e => ExtensionIdentifier . equals ( e . extensionId , extensionId ) ) ;
346
- if ( extensionStats ) {
347
- result . requestCount = extensionStats . requestCount ;
348
- result . tokenCount = extensionStats . tokenCount ;
349
- result . sessionRequestCount = extensionStats . sessionRequestCount ;
350
- result . sessionTokenCount = extensionStats . sessionTokenCount ;
351
- result . other . requestCount = extensionStats . requestCount ;
352
- result . other . tokenCount = extensionStats . tokenCount ;
353
- result . other . sessionRequestCount = extensionStats . sessionRequestCount ;
354
- result . other . sessionTokenCount = extensionStats . sessionTokenCount ;
355
- for ( const participant of extensionStats . participants ) {
356
- const agent = this . _chatAgentService . getAgent ( participant . id ) ;
357
- result . requestCount += participant . requestCount ;
358
- result . tokenCount += participant . tokenCount ;
359
- result . sessionRequestCount += participant . sessionRequestCount ;
360
- result . sessionTokenCount += participant . sessionTokenCount ;
361
- result . participants . splice ( agent ?. isDefault ? 0 : result . participants . length , 0 , {
362
- name : agent ?
363
- agent ?. isDefault ?
364
- agent . locations . includes ( ChatAgentLocation . Editor ) ? localize ( 'chat editor' , "Inline Chat (Editor)" ) : localize ( 'chat' , "Chat" )
365
- : `@${ agent . name } `
366
- : participant . id ,
367
- requestCount : participant . requestCount ,
368
- tokenCount : participant . tokenCount ,
369
- sessionRequestCount : participant . sessionRequestCount ,
370
- sessionTokenCount : participant . sessionTokenCount
371
- } ) ;
372
- }
373
- }
374
- return result ;
375
- }
376
- }
377
-
378
163
Registry . as < IExtensionFeaturesRegistry > ( Extensions . ExtensionFeaturesRegistry ) . registerExtensionFeature ( {
379
164
id : 'languageModels' ,
380
165
label : localize ( 'Language Models' , "Language Models" ) ,
381
166
description : localize ( 'languageModels' , "Language models usage statistics of this extension." ) ,
382
167
access : {
383
168
canToggle : false
384
169
} ,
385
- renderer : new SyncDescriptor ( LanguageModelFeatureRenderer ) ,
386
170
} ) ;
0 commit comments