1use std::sync::OnceLock;
2
3use collections::HashMap;
4use component::ComponentId;
5use gpui::{App, Entity, WeakEntity};
6use ui::{AnyElement, Component, ComponentScope, Window};
7use workspace::Workspace;
8
9use crate::ActiveThread;
10
11/// Function type for creating agent component previews
12pub type PreviewFn =
13 fn(WeakEntity<Workspace>, Entity<ActiveThread>, &mut Window, &mut App) -> Option<AnyElement>;
14
15pub struct AgentPreviewFn(fn() -> (ComponentId, PreviewFn));
16
17impl AgentPreviewFn {
18 pub const fn new(f: fn() -> (ComponentId, PreviewFn)) -> Self {
19 Self(f)
20 }
21}
22
23inventory::collect!(AgentPreviewFn);
24
25/// Trait that must be implemented by components that provide agent previews.
26pub trait AgentPreview: Component + Sized {
27 #[allow(unused)] // We can't know this is used due to the distributed slice
28 fn scope(&self) -> ComponentScope {
29 ComponentScope::Agent
30 }
31
32 /// Static method to create a preview for this component type
33 fn agent_preview(
34 workspace: WeakEntity<Workspace>,
35 active_thread: Entity<ActiveThread>,
36 window: &mut Window,
37 cx: &mut App,
38 ) -> Option<AnyElement>;
39}
40
41/// Register an agent preview for the given component type
42#[macro_export]
43macro_rules! register_agent_preview {
44 ($type:ty) => {
45 inventory::submit! {
46 $crate::ui::preview::AgentPreviewFn::new(|| {
47 (
48 <$type as component::Component>::id(),
49 <$type as $crate::ui::preview::AgentPreview>::agent_preview,
50 )
51 })
52 }
53 };
54}
55
56/// Lazy initialized registry of preview functions
57static AGENT_PREVIEW_REGISTRY: OnceLock<HashMap<ComponentId, PreviewFn>> = OnceLock::new();
58
59/// Initialize the agent preview registry if needed
60fn get_or_init_registry() -> &'static HashMap<ComponentId, PreviewFn> {
61 AGENT_PREVIEW_REGISTRY.get_or_init(|| {
62 let mut map = HashMap::default();
63 for register_fn in inventory::iter::<AgentPreviewFn>() {
64 let (id, preview_fn) = (register_fn.0)();
65 map.insert(id, preview_fn);
66 }
67 map
68 })
69}
70
71/// Get a specific agent preview by component ID.
72pub fn get_agent_preview(
73 id: &ComponentId,
74 workspace: WeakEntity<Workspace>,
75 active_thread: Entity<ActiveThread>,
76 window: &mut Window,
77 cx: &mut App,
78) -> Option<AnyElement> {
79 let registry = get_or_init_registry();
80 registry
81 .get(id)
82 .and_then(|preview_fn| preview_fn(workspace, active_thread, window, cx))
83}
84
85/// Get all registered agent previews.
86pub fn all_agent_previews() -> Vec<ComponentId> {
87 let registry = get_or_init_registry();
88 registry.keys().cloned().collect()
89}