@@ -18,6 +18,7 @@ import { IStorageService, StorageScope, StorageTarget } from '../../../../platfo
1818import { IChatAgentService } from './chatAgents.js' ;
1919import { ChatContextKeys } from './chatContextKeys.js' ;
2020import { ChatModeKind } from './constants.js' ;
21+ import { ICustomAgentData , ICustomAgentsService } from './customAgents.js' ;
2122import { IHandOff } from './promptSyntax/promptFileParser.js' ;
2223import { IAgentSource , ICustomAgent , IPromptsService , PromptsStorage } from './promptSyntax/service/promptsService.js' ;
2324
@@ -39,6 +40,7 @@ export class ChatModeService extends Disposable implements IChatModeService {
3940
4041 private readonly hasCustomModes : IContextKey < boolean > ;
4142 private readonly _customModeInstances = new Map < string , CustomChatMode > ( ) ;
43+ private readonly _apiCustomModeInstances = new Map < string , CustomChatMode > ( ) ;
4244
4345 private readonly _onDidChangeChatModes = new Emitter < void > ( ) ;
4446 public readonly onDidChangeChatModes = this . _onDidChangeChatModes . event ;
@@ -48,7 +50,8 @@ export class ChatModeService extends Disposable implements IChatModeService {
4850 @IChatAgentService private readonly chatAgentService : IChatAgentService ,
4951 @IContextKeyService contextKeyService : IContextKeyService ,
5052 @ILogService private readonly logService : ILogService ,
51- @IStorageService private readonly storageService : IStorageService
53+ @IStorageService private readonly storageService : IStorageService ,
54+ @ICustomAgentsService private readonly customAgentsService : ICustomAgentsService
5255 ) {
5356 super ( ) ;
5457
@@ -63,6 +66,9 @@ export class ChatModeService extends Disposable implements IChatModeService {
6366 } ) ) ;
6467 this . _register ( this . storageService . onWillSaveState ( ( ) => this . saveCachedModes ( ) ) ) ;
6568
69+ // Fetch custom agents from API
70+ void this . refreshApiCustomAgents ( true ) ;
71+
6672 // Ideally we can get rid of the setting to disable agent mode?
6773 let didHaveToolsAgent = this . chatAgentService . hasToolsAgent ;
6874 this . _register ( this . chatAgentService . onDidChangeAgents ( ( ) => {
@@ -155,11 +161,90 @@ export class ChatModeService extends Disposable implements IChatModeService {
155161 }
156162 }
157163
158- this . hasCustomModes . set ( this . _customModeInstances . size > 0 ) ;
164+ this . hasCustomModes . set ( this . _customModeInstances . size > 0 || this . _apiCustomModeInstances . size > 0 ) ;
159165 } catch ( error ) {
160166 this . logService . error ( error , 'Failed to load custom agents' ) ;
161167 this . _customModeInstances . clear ( ) ;
162- this . hasCustomModes . set ( false ) ;
168+ this . hasCustomModes . set ( this . _apiCustomModeInstances . size > 0 ) ;
169+ }
170+ if ( fireChangeEvent ) {
171+ this . _onDidChangeChatModes . fire ( ) ;
172+ }
173+ }
174+
175+ private async refreshApiCustomAgents ( fireChangeEvent ?: boolean ) : Promise < void > {
176+ try {
177+ const apiAgents = await this . customAgentsService . fetchCustomAgents ( {
178+ exclude_invalid_config : true ,
179+ dedupe : true
180+ } , CancellationToken . None ) ;
181+
182+ // Convert API agents to custom modes
183+ const seenIds = new Set < string > ( ) ;
184+
185+ // Add a test entry to verify the dropdown is working
186+ const testAgent : ICustomAgent = {
187+ uri : URI . parse ( 'api:test/test/test-agent' ) ,
188+ name : 'test-agent' ,
189+ description : 'Test agent from API' ,
190+ tools : [ '*' ] ,
191+ model : undefined ,
192+ argumentHint : undefined ,
193+ agentInstructions : {
194+ content : 'This is a test agent to verify API integration is working' ,
195+ toolReferences : [ ]
196+ } ,
197+ handOffs : undefined ,
198+ target : undefined ,
199+ source : { storage : PromptsStorage . local }
200+ } ;
201+ const testModeInstance = new CustomChatMode ( testAgent ) ;
202+ this . _apiCustomModeInstances . set ( 'api:test/test/test-agent' , testModeInstance ) ;
203+ seenIds . add ( 'api:test/test/test-agent' ) ;
204+
205+ for ( const apiAgent of apiAgents ) {
206+ const agentId = `api:${ apiAgent . repo_owner } /${ apiAgent . repo_name } /${ apiAgent . name } ` ;
207+ seenIds . add ( agentId ) ;
208+
209+ // Convert API agent to ICustomAgent format
210+ const customAgent : ICustomAgent = {
211+ uri : URI . parse ( agentId ) ,
212+ name : apiAgent . name ,
213+ description : apiAgent . description ,
214+ tools : apiAgent . tools ,
215+ model : undefined ,
216+ argumentHint : apiAgent . argument_hint ,
217+ agentInstructions : {
218+ content : apiAgent . description ,
219+ toolReferences : [ ] ,
220+ metadata : apiAgent . metadata
221+ } ,
222+ handOffs : undefined ,
223+ target : apiAgent . target ,
224+ source : { storage : PromptsStorage . local }
225+ } ;
226+
227+ let modeInstance = this . _apiCustomModeInstances . get ( agentId ) ;
228+ if ( modeInstance ) {
229+ modeInstance . updateData ( customAgent ) ;
230+ } else {
231+ modeInstance = new CustomChatMode ( customAgent ) ;
232+ this . _apiCustomModeInstances . set ( agentId , modeInstance ) ;
233+ }
234+ }
235+
236+ // Clean up instances for modes that no longer exist
237+ for ( const [ agentId ] of this . _apiCustomModeInstances . entries ( ) ) {
238+ if ( ! seenIds . has ( agentId ) ) {
239+ this . _apiCustomModeInstances . delete ( agentId ) ;
240+ }
241+ }
242+
243+ this . hasCustomModes . set ( this . _customModeInstances . size > 0 || this . _apiCustomModeInstances . size > 0 ) ;
244+ } catch ( error ) {
245+ this . logService . error ( error , 'Failed to load API custom agents' ) ;
246+ this . _apiCustomModeInstances . clear ( ) ;
247+ this . hasCustomModes . set ( this . _customModeInstances . size > 0 ) ;
163248 }
164249 if ( fireChangeEvent ) {
165250 this . _onDidChangeChatModes . fire ( ) ;
@@ -174,7 +259,9 @@ export class ChatModeService extends Disposable implements IChatModeService {
174259 }
175260
176261 findModeById ( id : string | ChatModeKind ) : IChatMode | undefined {
177- return this . getBuiltinModes ( ) . find ( mode => mode . id === id ) ?? this . _customModeInstances . get ( id ) ;
262+ return this . getBuiltinModes ( ) . find ( mode => mode . id === id ) ??
263+ this . _customModeInstances . get ( id ) ??
264+ this . _apiCustomModeInstances . get ( id ) ;
178265 }
179266
180267 findModeByName ( name : string ) : IChatMode | undefined {
@@ -194,7 +281,14 @@ export class ChatModeService extends Disposable implements IChatModeService {
194281 }
195282
196283 private getCustomModes ( ) : IChatMode [ ] {
197- return this . chatAgentService . hasToolsAgent ? Array . from ( this . _customModeInstances . values ( ) ) : [ ] ;
284+ if ( ! this . chatAgentService . hasToolsAgent ) {
285+ return [ ] ;
286+ }
287+ // Combine both local file-based custom modes and API-fetched custom agents
288+ return [
289+ ...Array . from ( this . _customModeInstances . values ( ) ) ,
290+ ...Array . from ( this . _apiCustomModeInstances . values ( ) )
291+ ] ;
198292 }
199293}
200294
0 commit comments