@@ -23,16 +23,18 @@ use language::LanguageRegistry;
2323use language_model:: {
2424 LanguageModelProvider , LanguageModelProviderId , LanguageModelRegistry , ZED_CLOUD_PROVIDER_ID ,
2525} ;
26+ use language_models:: AllLanguageModelSettings ;
2627use notifications:: status_toast:: { StatusToast , ToastIcon } ;
2728use project:: {
2829 agent_server_store:: { AgentServerStore , CLAUDE_CODE_NAME , CODEX_NAME , GEMINI_NAME } ,
2930 context_server_store:: { ContextServerConfiguration , ContextServerStatus , ContextServerStore } ,
3031} ;
3132use rope:: Rope ;
32- use settings:: { SettingsStore , update_settings_file} ;
33+ use settings:: { Settings , SettingsStore , update_settings_file} ;
3334use ui:: {
34- Chip , CommonAnimationExt , ContextMenu , Disclosure , Divider , DividerColor , ElevationIndex ,
35- Indicator , PopoverMenu , Switch , SwitchColor , Tooltip , WithScrollbar , prelude:: * ,
35+ Button , ButtonStyle , Chip , CommonAnimationExt , ContextMenu , Disclosure , Divider , DividerColor ,
36+ ElevationIndex , IconName , IconPosition , IconSize , Indicator , LabelSize , PopoverMenu , Switch ,
37+ SwitchColor , Tooltip , WithScrollbar , prelude:: * ,
3638} ;
3739use util:: ResultExt as _;
3840use workspace:: { Workspace , create_and_open_local_file} ;
@@ -304,10 +306,76 @@ impl AgentConfiguration {
304306 }
305307 } ) ) ,
306308 )
307- } ) ,
309+ } )
310+ . when (
311+ is_expanded && is_removable_provider ( & provider. id ( ) , cx) ,
312+ |this| {
313+ this. child (
314+ Button :: new (
315+ SharedString :: from ( format ! ( "delete-provider-{provider_id}" ) ) ,
316+ "Remove Provider" ,
317+ )
318+ . full_width ( )
319+ . style ( ButtonStyle :: Outlined )
320+ . icon_position ( IconPosition :: Start )
321+ . icon ( IconName :: Trash )
322+ . icon_size ( IconSize :: Small )
323+ . icon_color ( Color :: Muted )
324+ . label_size ( LabelSize :: Small )
325+ . on_click ( cx. listener ( {
326+ let provider = provider. clone ( ) ;
327+ move |this, _event, window, cx| {
328+ this. delete_provider ( provider. clone ( ) , window, cx) ;
329+ }
330+ } ) ) ,
331+ )
332+ } ,
333+ ) ,
308334 )
309335 }
310336
337+ fn delete_provider(
338+ & mut self,
339+ provider: Arc <dyn LanguageModelProvider >,
340+ window: & mut Window ,
341+ cx: & mut Context <Self >,
342+ ) {
343+ let fs = self . fs . clone ( ) ;
344+ let provider_id = provider. id ( ) ;
345+
346+ cx. spawn_in ( window, async move |_, cx| {
347+ cx. update ( |_window, cx| {
348+ update_settings_file ( fs. clone ( ) , cx, {
349+ let provider_id = provider_id. clone ( ) ;
350+ move |settings, _| {
351+ if let Some ( ref mut openai_compatible) = settings
352+ . language_models
353+ . as_mut ( )
354+ . and_then ( |lm| lm. openai_compatible . as_mut ( ) )
355+ {
356+ let key_to_remove: Arc < str > = Arc :: from ( provider_id. 0 . as_ref ( ) ) ;
357+ openai_compatible. remove ( & key_to_remove) ;
358+ }
359+ }
360+ } ) ;
361+ } )
362+ . log_err ( ) ;
363+
364+ cx. update ( |_window, cx| {
365+ LanguageModelRegistry :: global ( cx) . update ( cx, {
366+ let provider_id = provider_id. clone ( ) ;
367+ move |registry, cx| {
368+ registry. unregister_provider ( provider_id, cx) ;
369+ }
370+ } )
371+ } )
372+ . log_err ( ) ;
373+
374+ anyhow:: Ok ( ( ) )
375+ } )
376+ . detach_and_log_err ( cx) ;
377+ }
378+
311379 fn render_provider_configuration_section (
312380 & mut self ,
313381 cx : & mut Context < Self > ,
@@ -1225,3 +1293,14 @@ fn find_text_in_buffer(
12251293 None
12261294 }
12271295}
1296+
1297+ // OpenAI-compatible providers are user-configured and can be removed,
1298+ // whereas built-in providers (like Anthropic, OpenAI, Google, etc.) can't.
1299+ //
1300+ // If in the future we have more "API-compatible-type" of providers,
1301+ // they should be included here as removable providers.
1302+ fn is_removable_provider ( provider_id : & LanguageModelProviderId , cx : & App ) -> bool {
1303+ AllLanguageModelSettings :: get_global ( cx)
1304+ . openai_compatible
1305+ . contains_key ( provider_id. 0 . as_ref ( ) )
1306+ }
0 commit comments