ZIm/crates/agent_ui/src/ui/preview/agent_preview.rs
Max Brunsfeld 2283ec5de2
Extract an agent_ui crate from agent (#33284)
This PR moves the UI-dependent logic in the `agent` crate into its own
crate, `agent_ui`. The remaining `agent` crate no longer depends on
`editor`, `picker`, `ui`, `workspace`, etc.

This has compile time benefits, but the main motivation is to isolate
our core agentic logic, so that we can make agents more
pluggable/configurable.

Release Notes:

- N/A
2025-06-23 18:00:28 -07:00

89 lines
2.6 KiB
Rust

use std::sync::OnceLock;
use collections::HashMap;
use component::ComponentId;
use gpui::{App, Entity, WeakEntity};
use ui::{AnyElement, Component, ComponentScope, Window};
use workspace::Workspace;
use crate::ActiveThread;
/// Function type for creating agent component previews
pub type PreviewFn =
fn(WeakEntity<Workspace>, Entity<ActiveThread>, &mut Window, &mut App) -> Option<AnyElement>;
pub struct AgentPreviewFn(fn() -> (ComponentId, PreviewFn));
impl AgentPreviewFn {
pub const fn new(f: fn() -> (ComponentId, PreviewFn)) -> Self {
Self(f)
}
}
inventory::collect!(AgentPreviewFn);
/// Trait that must be implemented by components that provide agent previews.
pub trait AgentPreview: Component + Sized {
#[allow(unused)] // We can't know this is used due to the distributed slice
fn scope(&self) -> ComponentScope {
ComponentScope::Agent
}
/// Static method to create a preview for this component type
fn agent_preview(
workspace: WeakEntity<Workspace>,
active_thread: Entity<ActiveThread>,
window: &mut Window,
cx: &mut App,
) -> Option<AnyElement>;
}
/// Register an agent preview for the given component type
#[macro_export]
macro_rules! register_agent_preview {
($type:ty) => {
inventory::submit! {
$crate::ui::preview::AgentPreviewFn::new(|| {
(
<$type as component::Component>::id(),
<$type as $crate::ui::preview::AgentPreview>::agent_preview,
)
})
}
};
}
/// Lazy initialized registry of preview functions
static AGENT_PREVIEW_REGISTRY: OnceLock<HashMap<ComponentId, PreviewFn>> = OnceLock::new();
/// Initialize the agent preview registry if needed
fn get_or_init_registry() -> &'static HashMap<ComponentId, PreviewFn> {
AGENT_PREVIEW_REGISTRY.get_or_init(|| {
let mut map = HashMap::default();
for register_fn in inventory::iter::<AgentPreviewFn>() {
let (id, preview_fn) = (register_fn.0)();
map.insert(id, preview_fn);
}
map
})
}
/// Get a specific agent preview by component ID.
pub fn get_agent_preview(
id: &ComponentId,
workspace: WeakEntity<Workspace>,
active_thread: Entity<ActiveThread>,
window: &mut Window,
cx: &mut App,
) -> Option<AnyElement> {
let registry = get_or_init_registry();
registry
.get(id)
.and_then(|preview_fn| preview_fn(workspace, active_thread, window, cx))
}
/// Get all registered agent previews.
pub fn all_agent_previews() -> Vec<ComponentId> {
let registry = get_or_init_registry();
registry.keys().cloned().collect()
}