5
5
import { coalesceInPlace , isNonEmptyArray } from 'vs/base/common/arrays' ;
6
6
import { raceCancellation } from 'vs/base/common/async' ;
7
7
import { CancellationToken } from 'vs/base/common/cancellation' ;
8
- import { Codicon } from 'vs/base/common/codicons' ;
9
8
import { CancellationError } from 'vs/base/common/errors' ;
10
9
import { Emitter , Event } from 'vs/base/common/event' ;
11
10
import { MarkdownString } from 'vs/base/common/htmlContent' ;
12
11
import { Iterable } from 'vs/base/common/iterator' ;
13
- import { DisposableStore , IDisposable , MutableDisposable , toDisposable } from 'vs/base/common/lifecycle' ;
12
+ import { DisposableMap , DisposableStore , IDisposable , MutableDisposable , toDisposable } from 'vs/base/common/lifecycle' ;
14
13
import { LRUCache } from 'vs/base/common/map' ;
15
14
import { Schemas } from 'vs/base/common/network' ;
16
15
import { URI } from 'vs/base/common/uri' ;
17
16
import { generateUuid } from 'vs/base/common/uuid' ;
18
17
import { IActiveCodeEditor , ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
19
- import { Range } from 'vs/editor/common/core/range' ;
20
- import { TextEdit } from 'vs/editor/common/languages' ;
18
+ import { IRange , Range } from 'vs/editor/common/core/range' ;
19
+ import { TextEdit , WorkspaceEdit } from 'vs/editor/common/languages' ;
21
20
import { ITextModel , IValidEditOperation } from 'vs/editor/common/model' ;
22
21
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel' ;
23
22
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker' ;
24
23
import { IModelService } from 'vs/editor/common/services/model' ;
25
24
import { ITextModelService } from 'vs/editor/common/services/resolverService' ;
26
25
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
27
26
import { ILogService } from 'vs/platform/log/common/log' ;
28
- import { Progress } from 'vs/platform/progress/common/progress' ;
27
+ import { IProgress , Progress } from 'vs/platform/progress/common/progress' ;
29
28
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry' ;
30
29
import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor' ;
31
- import { ChatAgentLocation , IChatAgentCommand , IChatAgentData , IChatAgentHistoryEntry , IChatAgentImplementation , IChatAgentRequest , IChatAgentResult , IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents' ;
30
+ import { ChatAgentLocation , IChatAgent , IChatAgentCommand , IChatAgentData , IChatAgentHistoryEntry , IChatAgentImplementation , IChatAgentRequest , IChatAgentResult , IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents' ;
32
31
import { IChatFollowup , IChatProgress , IChatService , InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService' ;
33
- import { EditMode , IInlineChatBulkEditResponse , IInlineChatProgressItem , IInlineChatRequest , IInlineChatResponse , IInlineChatService , IInlineChatSession , InlineChatResponseFeedbackKind , InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat' ;
32
+ import { EditMode , IInlineChatBulkEditResponse , IInlineChatProgressItem , IInlineChatRequest , IInlineChatResponse , IInlineChatService , IInlineChatSession , IInlineChatSessionProvider , IInlineChatSlashCommand , InlineChatResponseFeedbackKind , InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat' ;
34
33
import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
35
- import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions' ;
36
34
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput' ;
37
35
import { EmptyResponse , ErrorResponse , HunkData , ReplyResponse , Session , SessionExchange , SessionWholeRange , StashedSession , TelemetryData , TelemetryDataClassification } from './inlineChatSession' ;
38
36
import { IInlineChatSessionEndEvent , IInlineChatSessionEvent , IInlineChatSessionService , ISessionKeyComputer , Recording } from './inlineChatSessionService' ;
39
37
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables' ;
38
+ import { ISelection } from 'vs/editor/common/core/selection' ;
39
+ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions' ;
40
+ import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions' ;
41
+ import { Codicon } from 'vs/base/common/codicons' ;
42
+ import { isEqual } from 'vs/base/common/resources' ;
40
43
41
44
class BridgeAgent implements IChatAgentImplementation {
42
45
@@ -186,7 +189,7 @@ class BridgeAgent implements IChatAgentImplementation {
186
189
return chatFollowups ;
187
190
}
188
191
189
- provideWelcomeMessage ( token : CancellationToken ) : string [ ] {
192
+ provideWelcomeMessage ( location : ChatAgentLocation , token : CancellationToken ) : string [ ] {
190
193
// without this provideSampleQuestions is not called
191
194
return [ ] ;
192
195
}
@@ -227,6 +230,17 @@ export class InlineChatError extends Error {
227
230
const _bridgeAgentId = 'brigde.editor' ;
228
231
const _inlineChatContext = '_inlineChatContext' ;
229
232
233
+ class InlineChatContext {
234
+
235
+ static readonly variableName = '_inlineChatContext' ;
236
+
237
+ constructor (
238
+ readonly uri : URI ,
239
+ readonly selection : ISelection ,
240
+ readonly wholeRange : IRange ,
241
+ ) { }
242
+ }
243
+
230
244
export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
231
245
232
246
declare _serviceBrand : undefined ;
@@ -265,6 +279,37 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
265
279
@IChatVariablesService chatVariableService : IChatVariablesService ,
266
280
) {
267
281
282
+ const fakeProviders = this . _store . add ( new DisposableMap < string , IDisposable > ( ) ) ;
283
+
284
+ this . _store . add ( this . _chatAgentService . onDidChangeAgents ( ( ) => {
285
+
286
+ const providersNow = new Set < string > ( ) ;
287
+
288
+ for ( const agent of this . _chatAgentService . getActivatedAgents ( ) ) {
289
+ if ( agent . id === _bridgeAgentId ) {
290
+ // not interesting
291
+ continue ;
292
+ }
293
+ if ( ! agent . locations . includes ( ChatAgentLocation . Editor ) || ! agent . isDefault ) {
294
+ // not interesting
295
+ continue ;
296
+ }
297
+ providersNow . add ( agent . id ) ;
298
+
299
+ if ( ! fakeProviders . has ( agent . id ) ) {
300
+ fakeProviders . set ( agent . id , _inlineChatService . addProvider ( _instaService . createInstance ( AgentInlineChatProvider , agent ) ) ) ;
301
+ this . _logService . info ( `ADDED inline chat provider for agent ${ agent . id } ` ) ;
302
+ }
303
+ }
304
+
305
+ for ( const [ id ] of fakeProviders ) {
306
+ if ( ! providersNow . has ( id ) ) {
307
+ fakeProviders . deleteAndDispose ( id ) ;
308
+ this . _logService . info ( `REMOVED inline chat provider for agent ${ id } ` ) ;
309
+ }
310
+ }
311
+ } ) ) ;
312
+
268
313
// MARK: register fake chat agent
269
314
const addOrRemoveBridgeAgent = ( ) => {
270
315
const that = this ;
@@ -339,10 +384,7 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
339
384
if ( data . session . chatModel === model ) {
340
385
return [ {
341
386
level : 'full' ,
342
- value : JSON . stringify ( {
343
- selection : data . editor . getSelection ( ) ,
344
- wholeRange : data . session . wholeRange . trackedInitialRange
345
- } )
387
+ value : JSON . stringify ( new InlineChatContext ( data . session . textModelN . uri , data . editor . getSelection ( ) ! , data . session . wholeRange . trackedInitialRange ) )
346
388
} ] ;
347
389
}
348
390
}
@@ -360,7 +402,21 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
360
402
361
403
async createSession ( editor : IActiveCodeEditor , options : { editMode : EditMode ; wholeRange ?: Range } , token : CancellationToken ) : Promise < Session | undefined > {
362
404
363
- const provider = Iterable . first ( this . _inlineChatService . getAllProvider ( ) ) ;
405
+ const agent = this . _chatAgentService . getDefaultAgent ( ChatAgentLocation . Editor ) ;
406
+ let provider : IInlineChatSessionProvider | undefined ;
407
+ if ( agent ) {
408
+ for ( const candidate of this . _inlineChatService . getAllProvider ( ) ) {
409
+ if ( candidate instanceof AgentInlineChatProvider && candidate . agent === agent ) {
410
+ provider = candidate ;
411
+ break ;
412
+ }
413
+ }
414
+ }
415
+
416
+ if ( ! provider ) {
417
+ provider = Iterable . first ( this . _inlineChatService . getAllProvider ( ) ) ;
418
+ }
419
+
364
420
if ( ! provider ) {
365
421
this . _logService . trace ( '[IE] NO provider found' ) ;
366
422
return undefined ;
@@ -684,3 +740,92 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
684
740
return this . _recordings ;
685
741
}
686
742
}
743
+
744
+ export class AgentInlineChatProvider implements IInlineChatSessionProvider {
745
+
746
+ readonly extensionId : ExtensionIdentifier ;
747
+ readonly label : string ;
748
+ readonly supportIssueReporting ?: boolean | undefined ;
749
+
750
+ constructor (
751
+ readonly agent : IChatAgent ,
752
+ @IChatAgentService private readonly _chatAgentService : IChatAgentService ,
753
+ ) {
754
+ this . label = agent . name ;
755
+ this . extensionId = agent . extensionId ;
756
+ this . supportIssueReporting = agent . metadata . supportIssueReporting ;
757
+ }
758
+
759
+ async prepareInlineChatSession ( model : ITextModel , range : ISelection , token : CancellationToken ) : Promise < IInlineChatSession > {
760
+
761
+ // TODO@jrieken have a good welcome message
762
+ // const welcomeMessage = await this.agent.provideWelcomeMessage?.(ChatAgentLocation.Editor, token);
763
+ // const message = welcomeMessage?.filter(candidate => typeof candidate === 'string').join(''),
764
+
765
+ return {
766
+ id : Math . random ( ) ,
767
+ wholeRange : new Range ( range . selectionStartLineNumber , range . selectionStartColumn , range . positionLineNumber , range . positionColumn ) ,
768
+ placeholder : this . agent . description ,
769
+ slashCommands : this . agent . slashCommands . map ( agentCommand => {
770
+ return {
771
+ command : agentCommand . name ,
772
+ detail : agentCommand . description ,
773
+ refer : agentCommand . name === 'explain' // TODO@jrieken @joyceerhl this should be cleaned up
774
+ } satisfies IInlineChatSlashCommand ;
775
+ } )
776
+ } ;
777
+ }
778
+
779
+ async provideResponse ( item : IInlineChatSession , request : IInlineChatRequest , progress : IProgress < IInlineChatProgressItem > , token : CancellationToken ) : Promise < IInlineChatResponse > {
780
+
781
+ const workspaceEdit : WorkspaceEdit = { edits : [ ] } ;
782
+
783
+ await this . _chatAgentService . invokeAgent ( this . agent . id , {
784
+ sessionId : String ( item . id ) ,
785
+ requestId : request . requestId ,
786
+ agentId : this . agent . id ,
787
+ message : request . prompt ,
788
+ location : ChatAgentLocation . Editor ,
789
+ variables : {
790
+ variables : [ {
791
+ name : InlineChatContext . variableName ,
792
+ values : [ {
793
+ level : 'full' ,
794
+ value : JSON . stringify ( new InlineChatContext ( request . previewDocument , request . selection , request . wholeRange ) )
795
+ } ]
796
+ } ]
797
+ }
798
+ } , part => {
799
+
800
+ if ( part . kind === 'markdownContent' ) {
801
+ progress . report ( { markdownFragment : part . content . value } ) ;
802
+ } else if ( part . kind === 'agentDetection' ) {
803
+ progress . report ( { slashCommand : part . command ?. name } ) ;
804
+ } else if ( part . kind === 'textEdit' ) {
805
+
806
+ if ( isEqual ( request . previewDocument , part . uri ) ) {
807
+ progress . report ( { edits : part . edits } ) ;
808
+ } else {
809
+ for ( const textEdit of part . edits ) {
810
+ workspaceEdit . edits . push ( { resource : part . uri , textEdit, versionId : undefined } ) ;
811
+ }
812
+ }
813
+ }
814
+
815
+ } , [ ] , token ) ;
816
+
817
+ return {
818
+ type : InlineChatResponseType . BulkEdit ,
819
+ id : Math . random ( ) ,
820
+ edits : workspaceEdit
821
+ } ;
822
+ }
823
+
824
+ // handleInlineChatResponseFeedback?(session: IInlineChatSession, response: IInlineChatResponse, kind: InlineChatResponseFeedbackKind): void {
825
+ // throw new Error('Method not implemented.');
826
+ // }
827
+
828
+ // provideFollowups?(session: IInlineChatSession, response: IInlineChatResponse, token: CancellationToken): ProviderResult<IInlineChatFollowup[]> {
829
+ // throw new Error('Method not implemented.');
830
+ // }
831
+ }
0 commit comments