agent_preview.rs

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