manage_profiles_modal.rs

  1mod profile_modal_header;
  2
  3use std::sync::Arc;
  4
  5use agent::ContextServerRegistry;
  6use agent_settings::{AgentProfile, AgentProfileId, AgentSettings, builtin_profiles};
  7use editor::Editor;
  8use fs::Fs;
  9use gpui::{DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Subscription, prelude::*};
 10use language_model::LanguageModel;
 11use settings::Settings as _;
 12use ui::{
 13    KeyBinding, ListItem, ListItemSpacing, ListSeparator, Navigable, NavigableEntry, prelude::*,
 14};
 15use workspace::{ModalView, Workspace};
 16
 17use crate::agent_configuration::manage_profiles_modal::profile_modal_header::ProfileModalHeader;
 18use crate::agent_configuration::tool_picker::{ToolPicker, ToolPickerDelegate};
 19use crate::{AgentPanel, ManageProfiles};
 20
 21enum Mode {
 22    ChooseProfile(ChooseProfileMode),
 23    NewProfile(NewProfileMode),
 24    ViewProfile(ViewProfileMode),
 25    ConfigureTools {
 26        profile_id: AgentProfileId,
 27        tool_picker: Entity<ToolPicker>,
 28        _subscription: Subscription,
 29    },
 30    ConfigureMcps {
 31        profile_id: AgentProfileId,
 32        tool_picker: Entity<ToolPicker>,
 33        _subscription: Subscription,
 34    },
 35}
 36
 37impl Mode {
 38    pub fn choose_profile(_window: &mut Window, cx: &mut Context<ManageProfilesModal>) -> Self {
 39        let settings = AgentSettings::get_global(cx);
 40
 41        let mut builtin_profiles = Vec::new();
 42        let mut custom_profiles = Vec::new();
 43
 44        for (profile_id, profile) in settings.profiles.iter() {
 45            let entry = ProfileEntry {
 46                id: profile_id.clone(),
 47                name: profile.name.clone(),
 48                navigation: NavigableEntry::focusable(cx),
 49            };
 50            if builtin_profiles::is_builtin(profile_id) {
 51                builtin_profiles.push(entry);
 52            } else {
 53                custom_profiles.push(entry);
 54            }
 55        }
 56
 57        builtin_profiles.sort_unstable_by(|a, b| a.name.cmp(&b.name));
 58        custom_profiles.sort_unstable_by(|a, b| a.name.cmp(&b.name));
 59
 60        Self::ChooseProfile(ChooseProfileMode {
 61            builtin_profiles,
 62            custom_profiles,
 63            add_new_profile: NavigableEntry::focusable(cx),
 64        })
 65    }
 66}
 67
 68#[derive(Clone)]
 69struct ProfileEntry {
 70    pub id: AgentProfileId,
 71    pub name: SharedString,
 72    pub navigation: NavigableEntry,
 73}
 74
 75#[derive(Clone)]
 76pub struct ChooseProfileMode {
 77    builtin_profiles: Vec<ProfileEntry>,
 78    custom_profiles: Vec<ProfileEntry>,
 79    add_new_profile: NavigableEntry,
 80}
 81
 82#[derive(Clone)]
 83pub struct ViewProfileMode {
 84    profile_id: AgentProfileId,
 85    fork_profile: NavigableEntry,
 86    configure_tools: NavigableEntry,
 87    configure_mcps: NavigableEntry,
 88    cancel_item: NavigableEntry,
 89}
 90
 91#[derive(Clone)]
 92pub struct NewProfileMode {
 93    name_editor: Entity<Editor>,
 94    base_profile_id: Option<AgentProfileId>,
 95}
 96
 97pub struct ManageProfilesModal {
 98    fs: Arc<dyn Fs>,
 99    context_server_registry: Entity<ContextServerRegistry>,
100    active_model: Option<Arc<dyn LanguageModel>>,
101    focus_handle: FocusHandle,
102    mode: Mode,
103}
104
105impl ManageProfilesModal {
106    pub fn register(
107        workspace: &mut Workspace,
108        _window: Option<&mut Window>,
109        _cx: &mut Context<Workspace>,
110    ) {
111        workspace.register_action(|workspace, action: &ManageProfiles, window, cx| {
112            if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
113                let fs = workspace.app_state().fs.clone();
114                let active_model = panel
115                    .read(cx)
116                    .active_native_agent_thread(cx)
117                    .and_then(|thread| thread.read(cx).model().cloned());
118
119                let context_server_registry = panel.read(cx).context_server_registry().clone();
120                workspace.toggle_modal(window, cx, |window, cx| {
121                    let mut this = Self::new(fs, active_model, context_server_registry, window, cx);
122
123                    if let Some(profile_id) = action.customize_tools.clone() {
124                        this.configure_builtin_tools(profile_id, window, cx);
125                    }
126
127                    this
128                })
129            }
130        });
131    }
132
133    pub fn new(
134        fs: Arc<dyn Fs>,
135        active_model: Option<Arc<dyn LanguageModel>>,
136        context_server_registry: Entity<ContextServerRegistry>,
137        window: &mut Window,
138        cx: &mut Context<Self>,
139    ) -> Self {
140        let focus_handle = cx.focus_handle();
141
142        Self {
143            fs,
144            active_model,
145            context_server_registry,
146            focus_handle,
147            mode: Mode::choose_profile(window, cx),
148        }
149    }
150
151    fn choose_profile(&mut self, window: &mut Window, cx: &mut Context<Self>) {
152        self.mode = Mode::choose_profile(window, cx);
153        self.focus_handle(cx).focus(window);
154    }
155
156    fn new_profile(
157        &mut self,
158        base_profile_id: Option<AgentProfileId>,
159        window: &mut Window,
160        cx: &mut Context<Self>,
161    ) {
162        let name_editor = cx.new(|cx| Editor::single_line(window, cx));
163        name_editor.update(cx, |editor, cx| {
164            editor.set_placeholder_text("Profile name", window, cx);
165        });
166
167        self.mode = Mode::NewProfile(NewProfileMode {
168            name_editor,
169            base_profile_id,
170        });
171        self.focus_handle(cx).focus(window);
172    }
173
174    pub fn view_profile(
175        &mut self,
176        profile_id: AgentProfileId,
177        window: &mut Window,
178        cx: &mut Context<Self>,
179    ) {
180        self.mode = Mode::ViewProfile(ViewProfileMode {
181            profile_id,
182            fork_profile: NavigableEntry::focusable(cx),
183            configure_tools: NavigableEntry::focusable(cx),
184            configure_mcps: NavigableEntry::focusable(cx),
185            cancel_item: NavigableEntry::focusable(cx),
186        });
187        self.focus_handle(cx).focus(window);
188    }
189
190    fn configure_mcp_tools(
191        &mut self,
192        profile_id: AgentProfileId,
193        window: &mut Window,
194        cx: &mut Context<Self>,
195    ) {
196        let settings = AgentSettings::get_global(cx);
197        let Some(profile) = settings.profiles.get(&profile_id).cloned() else {
198            return;
199        };
200
201        let tool_picker = cx.new(|cx| {
202            let delegate = ToolPickerDelegate::mcp_tools(
203                &self.context_server_registry,
204                self.fs.clone(),
205                profile_id.clone(),
206                profile,
207                cx,
208            );
209            ToolPicker::mcp_tools(delegate, window, cx)
210        });
211        let dismiss_subscription = cx.subscribe_in(&tool_picker, window, {
212            let profile_id = profile_id.clone();
213            move |this, _tool_picker, _: &DismissEvent, window, cx| {
214                this.view_profile(profile_id.clone(), window, cx);
215            }
216        });
217
218        self.mode = Mode::ConfigureMcps {
219            profile_id,
220            tool_picker,
221            _subscription: dismiss_subscription,
222        };
223        self.focus_handle(cx).focus(window);
224    }
225
226    fn configure_builtin_tools(
227        &mut self,
228        profile_id: AgentProfileId,
229        window: &mut Window,
230        cx: &mut Context<Self>,
231    ) {
232        let settings = AgentSettings::get_global(cx);
233        let Some(profile) = settings.profiles.get(&profile_id).cloned() else {
234            return;
235        };
236
237        let tool_picker = cx.new(|cx| {
238            let delegate = ToolPickerDelegate::builtin_tools(
239                //todo: This causes the web search tool to show up even it only works when using zed hosted models
240                agent::supported_built_in_tool_names(
241                    self.active_model.as_ref().map(|model| model.provider_id()),
242                )
243                .map(|s| s.into())
244                .collect::<Vec<_>>(),
245                self.fs.clone(),
246                profile_id.clone(),
247                profile,
248                cx,
249            );
250            ToolPicker::builtin_tools(delegate, window, cx)
251        });
252        let dismiss_subscription = cx.subscribe_in(&tool_picker, window, {
253            let profile_id = profile_id.clone();
254            move |this, _tool_picker, _: &DismissEvent, window, cx| {
255                this.view_profile(profile_id.clone(), window, cx);
256            }
257        });
258
259        self.mode = Mode::ConfigureTools {
260            profile_id,
261            tool_picker,
262            _subscription: dismiss_subscription,
263        };
264        self.focus_handle(cx).focus(window);
265    }
266
267    fn confirm(&mut self, window: &mut Window, cx: &mut Context<Self>) {
268        match &self.mode {
269            Mode::ChooseProfile { .. } => {}
270            Mode::NewProfile(mode) => {
271                let name = mode.name_editor.read(cx).text(cx);
272
273                let profile_id =
274                    AgentProfile::create(name, mode.base_profile_id.clone(), self.fs.clone(), cx);
275                self.view_profile(profile_id, window, cx);
276            }
277            Mode::ViewProfile(_) => {}
278            Mode::ConfigureTools { .. } => {}
279            Mode::ConfigureMcps { .. } => {}
280        }
281    }
282
283    fn cancel(&mut self, window: &mut Window, cx: &mut Context<Self>) {
284        match &self.mode {
285            Mode::ChooseProfile { .. } => {
286                cx.emit(DismissEvent);
287            }
288            Mode::NewProfile(mode) => {
289                if let Some(profile_id) = mode.base_profile_id.clone() {
290                    self.view_profile(profile_id, window, cx);
291                } else {
292                    self.choose_profile(window, cx);
293                }
294            }
295            Mode::ViewProfile(_) => self.choose_profile(window, cx),
296            Mode::ConfigureTools { profile_id, .. } => {
297                self.view_profile(profile_id.clone(), window, cx)
298            }
299            Mode::ConfigureMcps { profile_id, .. } => {
300                self.view_profile(profile_id.clone(), window, cx)
301            }
302        }
303    }
304}
305
306impl ModalView for ManageProfilesModal {}
307
308impl Focusable for ManageProfilesModal {
309    fn focus_handle(&self, cx: &App) -> FocusHandle {
310        match &self.mode {
311            Mode::ChooseProfile(_) => self.focus_handle.clone(),
312            Mode::NewProfile(mode) => mode.name_editor.focus_handle(cx),
313            Mode::ViewProfile(_) => self.focus_handle.clone(),
314            Mode::ConfigureTools { tool_picker, .. } => tool_picker.focus_handle(cx),
315            Mode::ConfigureMcps { tool_picker, .. } => tool_picker.focus_handle(cx),
316        }
317    }
318}
319
320impl EventEmitter<DismissEvent> for ManageProfilesModal {}
321
322impl ManageProfilesModal {
323    fn render_profile(
324        &self,
325        profile: &ProfileEntry,
326        window: &mut Window,
327        cx: &mut Context<Self>,
328    ) -> impl IntoElement + use<> {
329        let is_focused = profile.navigation.focus_handle.contains_focused(window, cx);
330
331        div()
332            .id(SharedString::from(format!("profile-{}", profile.id)))
333            .track_focus(&profile.navigation.focus_handle)
334            .on_action({
335                let profile_id = profile.id.clone();
336                cx.listener(move |this, _: &menu::Confirm, window, cx| {
337                    this.view_profile(profile_id.clone(), window, cx);
338                })
339            })
340            .child(
341                ListItem::new(SharedString::from(format!("profile-{}", profile.id)))
342                    .toggle_state(is_focused)
343                    .inset(true)
344                    .spacing(ListItemSpacing::Sparse)
345                    .child(Label::new(profile.name.clone()))
346                    .when(is_focused, |this| {
347                        this.end_slot(
348                            h_flex()
349                                .gap_1()
350                                .child(
351                                    Label::new("Customize")
352                                        .size(LabelSize::Small)
353                                        .color(Color::Muted),
354                                )
355                                .children(KeyBinding::for_action_in(
356                                    &menu::Confirm,
357                                    &self.focus_handle,
358                                    window,
359                                    cx,
360                                )),
361                        )
362                    })
363                    .on_click({
364                        let profile_id = profile.id.clone();
365                        cx.listener(move |this, _, window, cx| {
366                            this.view_profile(profile_id.clone(), window, cx);
367                        })
368                    }),
369            )
370    }
371
372    fn render_choose_profile(
373        &mut self,
374        mode: ChooseProfileMode,
375        window: &mut Window,
376        cx: &mut Context<Self>,
377    ) -> impl IntoElement {
378        Navigable::new(
379            div()
380                .track_focus(&self.focus_handle(cx))
381                .size_full()
382                .child(ProfileModalHeader::new("Agent Profiles", None))
383                .child(
384                    v_flex()
385                        .pb_1()
386                        .child(ListSeparator)
387                        .children(
388                            mode.builtin_profiles
389                                .iter()
390                                .map(|profile| self.render_profile(profile, window, cx)),
391                        )
392                        .when(!mode.custom_profiles.is_empty(), |this| {
393                            this.child(ListSeparator)
394                                .child(
395                                    div().pl_2().pb_1().child(
396                                        Label::new("Custom Profiles")
397                                            .size(LabelSize::Small)
398                                            .color(Color::Muted),
399                                    ),
400                                )
401                                .children(
402                                    mode.custom_profiles
403                                        .iter()
404                                        .map(|profile| self.render_profile(profile, window, cx)),
405                                )
406                        })
407                        .child(ListSeparator)
408                        .child(
409                            div()
410                                .id("new-profile")
411                                .track_focus(&mode.add_new_profile.focus_handle)
412                                .on_action(cx.listener(|this, _: &menu::Confirm, window, cx| {
413                                    this.new_profile(None, window, cx);
414                                }))
415                                .child(
416                                    ListItem::new("new-profile")
417                                        .toggle_state(
418                                            mode.add_new_profile
419                                                .focus_handle
420                                                .contains_focused(window, cx),
421                                        )
422                                        .inset(true)
423                                        .spacing(ListItemSpacing::Sparse)
424                                        .start_slot(Icon::new(IconName::Plus))
425                                        .child(Label::new("Add New Profile"))
426                                        .on_click({
427                                            cx.listener(move |this, _, window, cx| {
428                                                this.new_profile(None, window, cx);
429                                            })
430                                        }),
431                                ),
432                        ),
433                )
434                .into_any_element(),
435        )
436        .map(|mut navigable| {
437            for profile in mode.builtin_profiles {
438                navigable = navigable.entry(profile.navigation);
439            }
440            for profile in mode.custom_profiles {
441                navigable = navigable.entry(profile.navigation);
442            }
443
444            navigable
445        })
446        .entry(mode.add_new_profile)
447    }
448
449    fn render_new_profile(
450        &mut self,
451        mode: NewProfileMode,
452        _window: &mut Window,
453        cx: &mut Context<Self>,
454    ) -> impl IntoElement {
455        let settings = AgentSettings::get_global(cx);
456
457        let base_profile_name = mode.base_profile_id.as_ref().map(|base_profile_id| {
458            settings
459                .profiles
460                .get(base_profile_id)
461                .map(|profile| profile.name.clone())
462                .unwrap_or_else(|| "Unknown".into())
463        });
464
465        v_flex()
466            .id("new-profile")
467            .track_focus(&self.focus_handle(cx))
468            .child(ProfileModalHeader::new(
469                match &base_profile_name {
470                    Some(base_profile) => format!("Fork {base_profile}"),
471                    None => "New Profile".into(),
472                },
473                match base_profile_name {
474                    Some(_) => Some(IconName::Scissors),
475                    None => Some(IconName::Plus),
476                },
477            ))
478            .child(ListSeparator)
479            .child(h_flex().p_2().child(mode.name_editor))
480    }
481
482    fn render_view_profile(
483        &mut self,
484        mode: ViewProfileMode,
485        window: &mut Window,
486        cx: &mut Context<Self>,
487    ) -> impl IntoElement {
488        let settings = AgentSettings::get_global(cx);
489
490        let profile_name = settings
491            .profiles
492            .get(&mode.profile_id)
493            .map(|profile| profile.name.clone())
494            .unwrap_or_else(|| "Unknown".into());
495
496        let icon = match mode.profile_id.as_str() {
497            "write" => IconName::Pencil,
498            "ask" => IconName::Chat,
499            _ => IconName::UserRoundPen,
500        };
501
502        Navigable::new(
503            div()
504                .track_focus(&self.focus_handle(cx))
505                .size_full()
506                .child(ProfileModalHeader::new(profile_name, Some(icon)))
507                .child(
508                    v_flex()
509                        .pb_1()
510                        .child(ListSeparator)
511                        .child(
512                            div()
513                                .id("fork-profile")
514                                .track_focus(&mode.fork_profile.focus_handle)
515                                .on_action({
516                                    let profile_id = mode.profile_id.clone();
517                                    cx.listener(move |this, _: &menu::Confirm, window, cx| {
518                                        this.new_profile(Some(profile_id.clone()), window, cx);
519                                    })
520                                })
521                                .child(
522                                    ListItem::new("fork-profile")
523                                        .toggle_state(
524                                            mode.fork_profile
525                                                .focus_handle
526                                                .contains_focused(window, cx),
527                                        )
528                                        .inset(true)
529                                        .spacing(ListItemSpacing::Sparse)
530                                        .start_slot(
531                                            Icon::new(IconName::Scissors)
532                                                .size(IconSize::Small)
533                                                .color(Color::Muted),
534                                        )
535                                        .child(Label::new("Fork Profile"))
536                                        .on_click({
537                                            let profile_id = mode.profile_id.clone();
538                                            cx.listener(move |this, _, window, cx| {
539                                                this.new_profile(
540                                                    Some(profile_id.clone()),
541                                                    window,
542                                                    cx,
543                                                );
544                                            })
545                                        }),
546                                ),
547                        )
548                        .child(
549                            div()
550                                .id("configure-builtin-tools")
551                                .track_focus(&mode.configure_tools.focus_handle)
552                                .on_action({
553                                    let profile_id = mode.profile_id.clone();
554                                    cx.listener(move |this, _: &menu::Confirm, window, cx| {
555                                        this.configure_builtin_tools(
556                                            profile_id.clone(),
557                                            window,
558                                            cx,
559                                        );
560                                    })
561                                })
562                                .child(
563                                    ListItem::new("configure-builtin-tools-item")
564                                        .toggle_state(
565                                            mode.configure_tools
566                                                .focus_handle
567                                                .contains_focused(window, cx),
568                                        )
569                                        .inset(true)
570                                        .spacing(ListItemSpacing::Sparse)
571                                        .start_slot(
572                                            Icon::new(IconName::Settings)
573                                                .size(IconSize::Small)
574                                                .color(Color::Muted),
575                                        )
576                                        .child(Label::new("Configure Built-in Tools"))
577                                        .on_click({
578                                            let profile_id = mode.profile_id.clone();
579                                            cx.listener(move |this, _, window, cx| {
580                                                this.configure_builtin_tools(
581                                                    profile_id.clone(),
582                                                    window,
583                                                    cx,
584                                                );
585                                            })
586                                        }),
587                                ),
588                        )
589                        .child(
590                            div()
591                                .id("configure-mcps")
592                                .track_focus(&mode.configure_mcps.focus_handle)
593                                .on_action({
594                                    let profile_id = mode.profile_id.clone();
595                                    cx.listener(move |this, _: &menu::Confirm, window, cx| {
596                                        this.configure_mcp_tools(profile_id.clone(), window, cx);
597                                    })
598                                })
599                                .child(
600                                    ListItem::new("configure-mcp-tools")
601                                        .toggle_state(
602                                            mode.configure_mcps
603                                                .focus_handle
604                                                .contains_focused(window, cx),
605                                        )
606                                        .inset(true)
607                                        .spacing(ListItemSpacing::Sparse)
608                                        .start_slot(
609                                            Icon::new(IconName::ToolHammer)
610                                                .size(IconSize::Small)
611                                                .color(Color::Muted),
612                                        )
613                                        .child(Label::new("Configure MCP Tools"))
614                                        .on_click({
615                                            let profile_id = mode.profile_id.clone();
616                                            cx.listener(move |this, _, window, cx| {
617                                                this.configure_mcp_tools(
618                                                    profile_id.clone(),
619                                                    window,
620                                                    cx,
621                                                );
622                                            })
623                                        }),
624                                ),
625                        )
626                        .child(ListSeparator)
627                        .child(
628                            div()
629                                .id("cancel-item")
630                                .track_focus(&mode.cancel_item.focus_handle)
631                                .on_action({
632                                    cx.listener(move |this, _: &menu::Confirm, window, cx| {
633                                        this.cancel(window, cx);
634                                    })
635                                })
636                                .child(
637                                    ListItem::new("cancel-item")
638                                        .toggle_state(
639                                            mode.cancel_item
640                                                .focus_handle
641                                                .contains_focused(window, cx),
642                                        )
643                                        .inset(true)
644                                        .spacing(ListItemSpacing::Sparse)
645                                        .start_slot(
646                                            Icon::new(IconName::ArrowLeft)
647                                                .size(IconSize::Small)
648                                                .color(Color::Muted),
649                                        )
650                                        .child(Label::new("Go Back"))
651                                        .end_slot(
652                                            div().children(
653                                                KeyBinding::for_action_in(
654                                                    &menu::Cancel,
655                                                    &self.focus_handle,
656                                                    window,
657                                                    cx,
658                                                )
659                                                .map(|kb| kb.size(rems_from_px(12.))),
660                                            ),
661                                        )
662                                        .on_click({
663                                            cx.listener(move |this, _, window, cx| {
664                                                this.cancel(window, cx);
665                                            })
666                                        }),
667                                ),
668                        ),
669                )
670                .into_any_element(),
671        )
672        .entry(mode.fork_profile)
673        .entry(mode.configure_tools)
674        .entry(mode.configure_mcps)
675        .entry(mode.cancel_item)
676    }
677}
678
679impl Render for ManageProfilesModal {
680    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
681        let settings = AgentSettings::get_global(cx);
682
683        let go_back_item = div()
684            .id("cancel-item")
685            .track_focus(&self.focus_handle)
686            .on_action({
687                cx.listener(move |this, _: &menu::Confirm, window, cx| {
688                    this.cancel(window, cx);
689                })
690            })
691            .child(
692                ListItem::new("cancel-item")
693                    .toggle_state(self.focus_handle.contains_focused(window, cx))
694                    .inset(true)
695                    .spacing(ListItemSpacing::Sparse)
696                    .start_slot(
697                        Icon::new(IconName::ArrowLeft)
698                            .size(IconSize::Small)
699                            .color(Color::Muted),
700                    )
701                    .child(Label::new("Go Back"))
702                    .end_slot(
703                        div().children(
704                            KeyBinding::for_action_in(
705                                &menu::Cancel,
706                                &self.focus_handle,
707                                window,
708                                cx,
709                            )
710                            .map(|kb| kb.size(rems_from_px(12.))),
711                        ),
712                    )
713                    .on_click({
714                        cx.listener(move |this, _, window, cx| {
715                            this.cancel(window, cx);
716                        })
717                    }),
718            );
719
720        div()
721            .elevation_3(cx)
722            .w(rems(34.))
723            .key_context("ManageProfilesModal")
724            .on_action(cx.listener(|this, _: &menu::Cancel, window, cx| this.cancel(window, cx)))
725            .on_action(cx.listener(|this, _: &menu::Confirm, window, cx| this.confirm(window, cx)))
726            .capture_any_mouse_down(cx.listener(|this, _, window, cx| {
727                this.focus_handle(cx).focus(window);
728            }))
729            .on_mouse_down_out(cx.listener(|_this, _, _, cx| cx.emit(DismissEvent)))
730            .child(match &self.mode {
731                Mode::ChooseProfile(mode) => self
732                    .render_choose_profile(mode.clone(), window, cx)
733                    .into_any_element(),
734                Mode::NewProfile(mode) => self
735                    .render_new_profile(mode.clone(), window, cx)
736                    .into_any_element(),
737                Mode::ViewProfile(mode) => self
738                    .render_view_profile(mode.clone(), window, cx)
739                    .into_any_element(),
740                Mode::ConfigureTools {
741                    profile_id,
742                    tool_picker,
743                    ..
744                } => {
745                    let profile_name = settings
746                        .profiles
747                        .get(profile_id)
748                        .map(|profile| profile.name.clone())
749                        .unwrap_or_else(|| "Unknown".into());
750
751                    v_flex()
752                        .pb_1()
753                        .child(ProfileModalHeader::new(
754                            format!("{profile_name} — Configure Built-in Tools"),
755                            Some(IconName::Cog),
756                        ))
757                        .child(ListSeparator)
758                        .child(tool_picker.clone())
759                        .child(ListSeparator)
760                        .child(go_back_item)
761                        .into_any_element()
762                }
763                Mode::ConfigureMcps {
764                    profile_id,
765                    tool_picker,
766                    ..
767                } => {
768                    let profile_name = settings
769                        .profiles
770                        .get(profile_id)
771                        .map(|profile| profile.name.clone())
772                        .unwrap_or_else(|| "Unknown".into());
773
774                    v_flex()
775                        .pb_1()
776                        .child(ProfileModalHeader::new(
777                            format!("{profile_name} — Configure MCP Tools"),
778                            Some(IconName::ToolHammer),
779                        ))
780                        .child(ListSeparator)
781                        .child(tool_picker.clone())
782                        .child(ListSeparator)
783                        .child(go_back_item)
784                        .into_any_element()
785                }
786            })
787    }
788}