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