Skip to main content

everruns_a2ui/
catalog.rs

1//! A2UI Catalog and Category Definitions
2//!
3//! A Catalog is the agent-facing description of which components are available.
4//! Categories group components for readable prompt output.
5
6use crate::components::ComponentDef;
7
8/// One category of components in a catalog (e.g. "Layout", "Forms").
9pub struct ComponentCategory {
10    pub name: &'static str,
11    pub components: Vec<&'static str>,
12    /// Notes rendered after the category's component signatures.
13    pub notes: Vec<&'static str>,
14}
15
16/// A catalog describes the components an agent may emit.
17pub struct Catalog {
18    /// Hint for the recommended root component (typically "Card").
19    pub root_hint: &'static str,
20    pub components: Vec<ComponentDef>,
21    pub categories: Vec<ComponentCategory>,
22}
23
24/// Default category grouping for the built-in catalog.
25pub fn default_categories() -> Vec<ComponentCategory> {
26    vec![
27        ComponentCategory {
28            name: "Layout",
29            components: vec!["Card", "Stack", "Separator"],
30            notes: vec![],
31        },
32        ComponentCategory {
33            name: "Content",
34            components: vec!["Heading", "Text", "Callout", "Badge", "Image", "CodeBlock"],
35            notes: vec![],
36        },
37        ComponentCategory {
38            name: "Data",
39            components: vec!["List", "ListItem", "Table"],
40            notes: vec![],
41        },
42        ComponentCategory {
43            name: "Forms",
44            components: vec!["Form", "TextField", "Textarea", "Select", "Checkbox"],
45            notes: vec![
46                "Form submission posts a chat message (see `submitMessage`). \
47                 Form round-trips with typed responses are not yet supported.",
48            ],
49        },
50        ComponentCategory {
51            name: "Actions",
52            components: vec!["Button", "ButtonGroup"],
53            notes: vec![],
54        },
55    ]
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61    use std::collections::HashSet;
62
63    #[test]
64    fn categories_have_no_duplicates() {
65        let mut seen = HashSet::new();
66        for cat in default_categories() {
67            for c in cat.components {
68                assert!(seen.insert(c), "duplicate component across categories: {c}");
69            }
70        }
71    }
72
73    #[test]
74    fn categories_non_empty() {
75        for cat in default_categories() {
76            assert!(!cat.components.is_empty(), "empty category: {}", cat.name);
77        }
78    }
79}