@@ -17,14 +17,12 @@ import { autorun, derived, IObservable, ObservableMap } from '../../../../base/c
17
17
import { StopWatch } from '../../../../base/common/stopwatch.js' ;
18
18
import { URI } from '../../../../base/common/uri.js' ;
19
19
import { OffsetRange } from '../../../../editor/common/core/ranges/offsetRange.js' ;
20
- import { isLocation } from '../../../../editor/common/languages.js' ;
21
20
import { localize } from '../../../../nls.js' ;
22
21
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js' ;
23
22
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js' ;
24
23
import { ILogService } from '../../../../platform/log/common/log.js' ;
25
24
import { Progress } from '../../../../platform/progress/common/progress.js' ;
26
25
import { IStorageService , StorageScope , StorageTarget } from '../../../../platform/storage/common/storage.js' ;
27
- import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js' ;
28
26
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js' ;
29
27
import { IExtensionService } from '../../../services/extensions/common/extensions.js' ;
30
28
import { IMcpService } from '../../mcp/common/mcpTypes.js' ;
@@ -33,15 +31,15 @@ import { ChatModel, ChatRequestModel, ChatRequestRemovalReason, IChatModel, ICha
33
31
import { chatAgentLeader , ChatRequestAgentPart , ChatRequestAgentSubcommandPart , ChatRequestSlashCommandPart , ChatRequestTextPart , chatSubcommandLeader , getPromptText , IParsedChatRequest } from './chatParserTypes.js' ;
34
32
import { ChatRequestParser } from './chatRequestParser.js' ;
35
33
import { IChatCompleteResponse , IChatDetail , IChatFollowup , IChatProgress , IChatSendRequestData , IChatSendRequestOptions , IChatSendRequestResponseState , IChatService , IChatTransferredSessionData , IChatUserActionEvent } from './chatService.js' ;
36
- import { ChatServiceTelemetry } from './chatServiceTelemetry.js' ;
34
+ import { ChatRequestTelemetry , ChatServiceTelemetry } from './chatServiceTelemetry.js' ;
37
35
import { IChatSessionsService } from './chatSessionsService.js' ;
38
36
import { ChatSessionStore , IChatTransfer2 } from './chatSessionStore.js' ;
39
37
import { IChatSlashCommandService } from './chatSlashCommands.js' ;
40
38
import { IChatTransferService } from './chatTransferService.js' ;
41
39
import { ChatSessionUri } from './chatUri.js' ;
42
- import { IChatRequestVariableEntry , isImageVariableEntry } from './chatVariableEntries.js' ;
40
+ import { IChatRequestVariableEntry } from './chatVariableEntries.js' ;
43
41
import { ChatAgentLocation , ChatConfiguration , ChatModeKind } from './constants.js' ;
44
- import { ChatMessageRole , IChatMessage , ILanguageModelsService } from './languageModels.js' ;
42
+ import { ChatMessageRole , IChatMessage } from './languageModels.js' ;
45
43
import { ILanguageModelToolsService } from './languageModelToolsService.js' ;
46
44
47
45
const serializedChatKey = 'interactive.sessions' ;
@@ -50,44 +48,6 @@ const globalChatKey = 'chat.workspaceTransfer';
50
48
51
49
const SESSION_TRANSFER_EXPIRATION_IN_MILLISECONDS = 1000 * 60 ;
52
50
53
- type ChatProviderInvokedEvent = {
54
- timeToFirstProgress : number | undefined ;
55
- totalTime : number | undefined ;
56
- result : 'success' | 'error' | 'errorWithOutput' | 'cancelled' | 'filtered' ;
57
- requestType : 'string' | 'followup' | 'slashCommand' ;
58
- chatSessionId : string ;
59
- agent : string ;
60
- agentExtensionId : string | undefined ;
61
- slashCommand : string | undefined ;
62
- location : ChatAgentLocation ;
63
- citations : number ;
64
- numCodeBlocks : number ;
65
- isParticipantDetected : boolean ;
66
- enableCommandDetection : boolean ;
67
- attachmentKinds : string [ ] ;
68
- model : string | undefined ;
69
- } ;
70
-
71
- type ChatProviderInvokedClassification = {
72
- timeToFirstProgress : { classification : 'SystemMetaData' ; purpose : 'PerformanceAndHealth' ; comment : 'The time in milliseconds from invoking the provider to getting the first data.' } ;
73
- totalTime : { classification : 'SystemMetaData' ; purpose : 'PerformanceAndHealth' ; comment : 'The total time it took to run the provider\'s `provideResponseWithProgress`.' } ;
74
- result : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'Whether invoking the ChatProvider resulted in an error.' } ;
75
- requestType : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The type of request that the user made.' } ;
76
- chatSessionId : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'A random ID for the session.' } ;
77
- agent : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The type of agent used.' } ;
78
- agentExtensionId : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The extension that contributed the agent.' } ;
79
- slashCommand ?: { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The type of slashCommand used.' } ;
80
- location : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The location at which chat request was made.' } ;
81
- citations : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The number of public code citations that were returned with the response.' } ;
82
- numCodeBlocks : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The number of code blocks in the response.' } ;
83
- isParticipantDetected : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'Whether the participant was automatically detected.' } ;
84
- enableCommandDetection : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'Whether participation detection was disabled for this invocation.' } ;
85
- attachmentKinds : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The types of variables/attachments that the user included with their query.' } ;
86
- model : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'The model used to generate the response.' } ;
87
- owner : 'roblourens' ;
88
- comment : 'Provides insight into the performance of Chat agents.' ;
89
- } ;
90
-
91
51
const maxPersistedSessions = 25 ;
92
52
93
53
class CancellableRequest implements IDisposable {
@@ -160,13 +120,11 @@ export class ChatService extends Disposable implements IChatService {
160
120
@ILogService private readonly logService : ILogService ,
161
121
@IExtensionService private readonly extensionService : IExtensionService ,
162
122
@IInstantiationService private readonly instantiationService : IInstantiationService ,
163
- @ITelemetryService private readonly telemetryService : ITelemetryService ,
164
123
@IWorkspaceContextService private readonly workspaceContextService : IWorkspaceContextService ,
165
124
@IChatSlashCommandService private readonly chatSlashCommandService : IChatSlashCommandService ,
166
125
@IChatAgentService private readonly chatAgentService : IChatAgentService ,
167
126
@IConfigurationService private readonly configurationService : IConfigurationService ,
168
127
@IChatTransferService private readonly chatTransferService : IChatTransferService ,
169
- @ILanguageModelsService private readonly languageModelsService : ILanguageModelsService ,
170
128
@IChatSessionsService private readonly chatSessionService : IChatSessionsService ,
171
129
@IMcpService private readonly mcpService : IMcpService ,
172
130
) {
@@ -550,8 +508,6 @@ export class ChatService extends Disposable implements IChatService {
550
508
551
509
const isTransferred = this . transferredSessionData ?. sessionId === sessionId ;
552
510
if ( isTransferred ) {
553
- // TODO
554
- // this.chatAgentService.toggleToolsAgentMode(this.transferredSessionData.toolsAgentModeEnabled);
555
511
this . _transferredSessionData = undefined ;
556
512
}
557
513
@@ -779,6 +735,15 @@ export class ChatService extends Disposable implements IChatService {
779
735
const agentSlashCommandPart = 'kind' in parsedRequest ? undefined : parsedRequest . parts . find ( ( r ) : r is ChatRequestAgentSubcommandPart => r instanceof ChatRequestAgentSubcommandPart ) ;
780
736
const commandPart = 'kind' in parsedRequest ? undefined : parsedRequest . parts . find ( ( r ) : r is ChatRequestSlashCommandPart => r instanceof ChatRequestSlashCommandPart ) ;
781
737
const requests = [ ...model . getRequests ( ) ] ;
738
+ const requestTelemetry = this . instantiationService . createInstance ( ChatRequestTelemetry , {
739
+ agentPart,
740
+ agentSlashCommandPart,
741
+ commandPart,
742
+ sessionId : model . sessionId ,
743
+ location : model . initialLocation ,
744
+ options,
745
+ enableCommandDetection
746
+ } ) ;
782
747
783
748
let gotProgress = false ;
784
749
const requestType = commandPart ? 'slashCommand' : 'string' ;
@@ -828,23 +793,14 @@ export class ChatService extends Disposable implements IChatService {
828
793
return ;
829
794
}
830
795
831
- this . telemetryService . publicLog2 < ChatProviderInvokedEvent , ChatProviderInvokedClassification > ( 'interactiveSessionProviderInvoked' , {
796
+ requestTelemetry . complete ( {
832
797
timeToFirstProgress : undefined ,
798
+ result : 'cancelled' ,
833
799
// Normally timings happen inside the EH around the actual provider. For cancellation we can measure how long the user waited before cancelling
834
800
totalTime : stopWatch . elapsed ( ) ,
835
- result : 'cancelled' ,
836
801
requestType,
837
- agent : detectedAgent ?. id ?? agentPart ?. agent . id ?? '' ,
838
- agentExtensionId : detectedAgent ?. extensionId . value ?? agentPart ?. agent . extensionId . value ?? '' ,
839
- slashCommand : agentSlashCommandPart ? agentSlashCommandPart . command . name : commandPart ?. slashCommand . command ,
840
- chatSessionId : model . sessionId ,
841
- location,
842
- citations : request ?. response ?. codeCitations . length ?? 0 ,
843
- numCodeBlocks : getCodeBlocks ( request . response ?. response . toString ( ) ?? '' ) . length ,
844
- isParticipantDetected : ! ! detectedAgent ,
845
- enableCommandDetection,
846
- attachmentKinds : this . attachmentKindsForTelemetry ( request . variableData ) ,
847
- model : this . resolveModelId ( options ?. userSelectedModelId ) ,
802
+ detectedAgent,
803
+ request,
848
804
} ) ;
849
805
850
806
model . cancelRequest ( request ) ;
@@ -982,24 +938,16 @@ export class ChatService extends Disposable implements IChatService {
982
938
rawResult . errorDetails && gotProgress ? 'errorWithOutput' :
983
939
rawResult . errorDetails ? 'error' :
984
940
'success' ;
985
- const commandForTelemetry = agentSlashCommandPart ? agentSlashCommandPart . command . name : commandPart ?. slashCommand . command ;
986
- this . telemetryService . publicLog2 < ChatProviderInvokedEvent , ChatProviderInvokedClassification > ( 'interactiveSessionProviderInvoked' , {
941
+
942
+ requestTelemetry . complete ( {
987
943
timeToFirstProgress : rawResult . timings ?. firstProgress ,
988
944
totalTime : rawResult . timings ?. totalElapsed ,
989
945
result,
990
946
requestType,
991
- agent : detectedAgent ?. id ?? agentPart ?. agent . id ?? '' ,
992
- agentExtensionId : detectedAgent ?. extensionId . value ?? agentPart ?. agent . extensionId . value ?? '' ,
993
- slashCommand : commandForTelemetry ,
994
- chatSessionId : model . sessionId ,
995
- enableCommandDetection,
996
- isParticipantDetected : ! ! detectedAgent ,
997
- location,
998
- citations : request . response ?. codeCitations . length ?? 0 ,
999
- numCodeBlocks : getCodeBlocks ( request . response ?. response . toString ( ) ?? '' ) . length ,
1000
- attachmentKinds : this . attachmentKindsForTelemetry ( request . variableData ) ,
1001
- model : this . resolveModelId ( options ?. userSelectedModelId ) ,
947
+ detectedAgent,
948
+ request,
1002
949
} ) ;
950
+
1003
951
model . setResponse ( request , rawResult ) ;
1004
952
completeResponseCreated ( ) ;
1005
953
this . trace ( 'sendRequest' , `Provider returned response for session ${ model . sessionId } ` ) ;
@@ -1008,6 +956,7 @@ export class ChatService extends Disposable implements IChatService {
1008
956
if ( agentOrCommandFollowups ) {
1009
957
agentOrCommandFollowups . then ( followups => {
1010
958
model . setFollowups ( request , followups ) ;
959
+ const commandForTelemetry = agentSlashCommandPart ? agentSlashCommandPart . command . name : commandPart ?. slashCommand . command ;
1011
960
this . _chatServiceTelemetry . retrievedFollowups ( agentPart ?. agent . id ?? '' , commandForTelemetry , followups ?. length ?? 0 ) ;
1012
961
} ) ;
1013
962
}
@@ -1019,23 +968,13 @@ export class ChatService extends Disposable implements IChatService {
1019
968
}
1020
969
} catch ( err ) {
1021
970
this . logService . error ( `Error while handling chat request: ${ toErrorMessage ( err , true ) } ` ) ;
1022
- const result = 'error' ;
1023
- this . telemetryService . publicLog2 < ChatProviderInvokedEvent , ChatProviderInvokedClassification > ( 'interactiveSessionProviderInvoked' , {
971
+ requestTelemetry . complete ( {
1024
972
timeToFirstProgress : undefined ,
1025
973
totalTime : undefined ,
1026
- result,
974
+ result : 'error' ,
1027
975
requestType,
1028
- agent : detectedAgent ?. id ?? agentPart ?. agent . id ?? '' ,
1029
- agentExtensionId : detectedAgent ?. extensionId . value ?? agentPart ?. agent . extensionId . value ?? '' ,
1030
- slashCommand : agentSlashCommandPart ? agentSlashCommandPart . command . name : commandPart ?. slashCommand . command ,
1031
- chatSessionId : model . sessionId ,
1032
- location,
1033
- citations : 0 ,
1034
- numCodeBlocks : 0 ,
1035
- enableCommandDetection,
1036
- isParticipantDetected : ! ! detectedAgent ,
1037
- attachmentKinds : request ? this . attachmentKindsForTelemetry ( request . variableData ) : [ ] ,
1038
- model : this . resolveModelId ( options ?. userSelectedModelId )
976
+ detectedAgent,
977
+ request,
1039
978
} ) ;
1040
979
if ( request ) {
1041
980
const rawResult : IChatAgentResult = { errorDetails : { message : err . message } } ;
@@ -1060,10 +999,6 @@ export class ChatService extends Disposable implements IChatService {
1060
999
} ;
1061
1000
}
1062
1001
1063
- private resolveModelId ( userSelectedModelId : string | undefined ) : string | undefined {
1064
- return userSelectedModelId && this . languageModelsService . lookupLanguageModel ( userSelectedModelId ) ?. id ;
1065
- }
1066
-
1067
1002
private prepareContext ( attachedContextVariables : IChatRequestVariableEntry [ ] | undefined ) : IChatRequestVariableEntry [ ] {
1068
1003
attachedContextVariables ??= [ ] ;
1069
1004
@@ -1085,44 +1020,6 @@ export class ChatService extends Disposable implements IChatService {
1085
1020
return attachedContextVariables ;
1086
1021
}
1087
1022
1088
- private attachmentKindsForTelemetry ( variableData : IChatRequestVariableData ) : string [ ] {
1089
- // TODO this shows why attachments still have to be cleaned up somewhat
1090
- return variableData . variables . map ( v => {
1091
- if ( v . kind === 'implicit' ) {
1092
- return 'implicit' ;
1093
- } else if ( v . range ) {
1094
- // 'range' is range within the prompt text
1095
- if ( v . kind === 'tool' ) {
1096
- return 'toolInPrompt' ;
1097
- } else if ( v . kind === 'toolset' ) {
1098
- return 'toolsetInPrompt' ;
1099
- } else {
1100
- return 'fileInPrompt' ;
1101
- }
1102
- } else if ( v . kind === 'command' ) {
1103
- return 'command' ;
1104
- } else if ( v . kind === 'symbol' ) {
1105
- return 'symbol' ;
1106
- } else if ( isImageVariableEntry ( v ) ) {
1107
- return 'image' ;
1108
- } else if ( v . kind === 'directory' ) {
1109
- return 'directory' ;
1110
- } else if ( v . kind === 'tool' ) {
1111
- return 'tool' ;
1112
- } else if ( v . kind === 'toolset' ) {
1113
- return 'toolset' ;
1114
- } else {
1115
- if ( URI . isUri ( v . value ) ) {
1116
- return 'file' ;
1117
- } else if ( isLocation ( v . value ) ) {
1118
- return 'location' ;
1119
- } else {
1120
- return 'otherAttachment' ;
1121
- }
1122
- }
1123
- } ) ;
1124
- }
1125
-
1126
1023
private getHistoryEntriesFromModel ( requests : IChatRequestModel [ ] , sessionId : string , location : ChatAgentLocation , forAgentId : string ) : IChatAgentHistoryEntry [ ] {
1127
1024
const history : IChatAgentHistoryEntry [ ] = [ ] ;
1128
1025
const agent = this . chatAgentService . getAgent ( forAgentId ) ;
@@ -1294,26 +1191,3 @@ export class ChatService extends Disposable implements IChatService {
1294
1191
this . _chatSessionStore . logIndex ( ) ;
1295
1192
}
1296
1193
}
1297
-
1298
- function getCodeBlocks ( text : string ) : string [ ] {
1299
- const lines = text . split ( '\n' ) ;
1300
- const codeBlockLanguages : string [ ] = [ ] ;
1301
-
1302
- let codeBlockState : undefined | { readonly delimiter : string ; readonly languageId : string } ;
1303
- for ( let i = 0 ; i < lines . length ; i ++ ) {
1304
- const line = lines [ i ] ;
1305
-
1306
- if ( codeBlockState ) {
1307
- if ( new RegExp ( `^\\s*${ codeBlockState . delimiter } \\s*$` ) . test ( line ) ) {
1308
- codeBlockLanguages . push ( codeBlockState . languageId ) ;
1309
- codeBlockState = undefined ;
1310
- }
1311
- } else {
1312
- const match = line . match ( / ^ ( \s * ) ( ` { 3 , } | ~ { 3 , } ) ( \w * ) / ) ;
1313
- if ( match ) {
1314
- codeBlockState = { delimiter : match [ 2 ] , languageId : match [ 3 ] } ;
1315
- }
1316
- }
1317
- }
1318
- return codeBlockLanguages ;
1319
- }
0 commit comments