@@ -22,11 +22,16 @@ def escape_mdx(text: str) -> str:
2222 return text .replace ('<' , '<' ).replace ('>' , '>' ).replace ('{' , '{' ).replace ('}' , '}' )
2323
2424
25- def sanitize_description (text : str ) -> str :
26- """Sanitize description for frontmatter."""
25+ def sanitize_description (text : str , max_len : int = 150 ) -> str :
26+ """Sanitize description for frontmatter. Truncates at word boundary. """
2727 if not text :
2828 return ""
29- return text .replace ('"' , "'" ).replace ('\n ' , ' ' )[:150 ]
29+ clean = text .replace ('"' , "'" ).replace ('\n ' , ' ' ).strip ()
30+ if len (clean ) <= max_len :
31+ return clean
32+ # Truncate at word boundary
33+ truncated = clean [:max_len ].rsplit (' ' , 1 )[0 ]
34+ return truncated + "..."
3035
3136
3237# Icon map
@@ -38,6 +43,110 @@ def sanitize_description(text: str) -> str:
3843 "commands" : "terminal" , "default" : "file-code"
3944}
4045
46+ # Friendly title mappings for modules
47+ MODULE_TITLES = {
48+ "agent" : "Agent" ,
49+ "builder" : "Agent Builder" ,
50+ "config" : "Configuration" ,
51+ "error" : "Error Handling" ,
52+ "llm" : "LLM Providers" ,
53+ "memory" : "Memory" ,
54+ "tools" : "Tools" ,
55+ "workflows" : "Workflows" ,
56+ "praisonai_derive" : "Derive Macros" ,
57+ "chat" : "Chat Command" ,
58+ "prompt" : "Prompt Command" ,
59+ "run" : "Run Command" ,
60+ }
61+
62+ # Rich descriptions for modules (used when docstring is empty or as fallback)
63+ MODULE_DESCRIPTIONS = {
64+ "agent" : "Core AI Agent implementation for building intelligent agents in Rust" ,
65+ "builder" : "Fluent builder pattern for constructing Rust AI agents" ,
66+ "config" : "Configuration types for PraisonAI Rust AI agents" ,
67+ "error" : "Error handling utilities for Rust AI agent operations" ,
68+ "llm" : "LLM provider abstractions for Rust AI agents (OpenAI, Anthropic, Ollama)" ,
69+ "memory" : "Memory and conversation history for Rust AI agents" ,
70+ "tools" : "Tool system for extending Rust AI agent capabilities" ,
71+ "workflows" : "Multi-agent workflow patterns for Rust AI orchestration" ,
72+ "praisonai_derive" : "Procedural macros for defining Rust AI agent tools" ,
73+ "chat" : "Interactive chat command for Rust AI agents" ,
74+ "prompt" : "Single-shot prompt execution for Rust AI agents" ,
75+ "run" : "Workflow execution command for Rust AI agents" ,
76+ }
77+
78+ # Abbreviations to preserve in titles
79+ ABBREVIATIONS = {"llm" , "api" , "cli" , "id" , "url" , "http" , "ai" , "io" }
80+
81+
82+ def friendly_title (name : str , page_type : str = "class" ) -> str :
83+ """Convert a name to a friendly, human-readable title.
84+
85+ Args:
86+ name: The raw name (e.g., "AgentBuilder", "praisonai_derive")
87+ page_type: One of "module", "class", "function"
88+ """
89+ # Check for explicit module title mapping
90+ if page_type == "module" and name .lower () in MODULE_TITLES :
91+ return MODULE_TITLES [name .lower ()]
92+
93+ # For functions, add parentheses
94+ if page_type == "function" :
95+ # Special case for macros
96+ if name == "tool" :
97+ return "#[tool] Macro"
98+ return f"{ name } ()"
99+
100+ # Convert snake_case to Title Case
101+ if "_" in name :
102+ parts = name .split ("_" )
103+ titled_parts = []
104+ for part in parts :
105+ if part .lower () in ABBREVIATIONS :
106+ titled_parts .append (part .upper ())
107+ else :
108+ titled_parts .append (part .capitalize ())
109+ return " " .join (titled_parts )
110+
111+ # Convert PascalCase to Title Case with spaces
112+ # e.g., "AgentBuilder" -> "Agent Builder", "LlmConfig" -> "LLM Config"
113+ result = []
114+ current_word = []
115+
116+ for i , char in enumerate (name ):
117+ if char .isupper ():
118+ # Check if this is part of an abbreviation
119+ if current_word :
120+ word = "" .join (current_word )
121+ # If previous chars form an abbreviation, keep them together
122+ if word .lower () in ABBREVIATIONS :
123+ result .append (word .upper ())
124+ else :
125+ result .append (word )
126+ current_word = []
127+ current_word .append (char )
128+ else :
129+ current_word .append (char )
130+
131+ # Don't forget the last word
132+ if current_word :
133+ word = "" .join (current_word )
134+ if word .lower () in ABBREVIATIONS :
135+ result .append (word .upper ())
136+ else :
137+ result .append (word )
138+
139+ # Join and fix common patterns
140+ title = " " .join (result )
141+
142+ # Fix cases like "L L M" -> "LLM"
143+ for abbr in ABBREVIATIONS :
144+ spaced = " " .join (abbr .upper ())
145+ if spaced in title :
146+ title = title .replace (spaced , abbr .upper ())
147+
148+ return title
149+
41150
42151def get_icon (name : str ) -> str :
43152 """Get icon for module name."""
@@ -47,17 +156,21 @@ def get_icon(name: str) -> str:
47156def generate_module_page (info , output_dir : Path , dry_run : bool = False ) -> str :
48157 """Generate a module hub page."""
49158 short_name = info .short_name or info .name .split ('.' )[- 1 ]
50- desc = sanitize_description (info .docstring ) or f"Rust module { short_name } "
159+ title = friendly_title (short_name , "module" )
160+ title_suffix = " • Rust AI Agent SDK"
161+ # Use docstring if available, otherwise use our rich descriptions
162+ desc = sanitize_description (info .docstring ) or MODULE_DESCRIPTIONS .get (short_name .lower (), f"Rust AI Agent SDK - { title } " )
51163
52164 content = f'''---
53- title: "{ short_name } "
165+ title: "{ title } { title_suffix } "
166+ sidebarTitle: "{ title } "
54167description: "{ desc } "
55168icon: "{ get_icon (short_name )} "
56169---
57170
58- # { info . name }
171+ # { short_name }
59172
60- <Badge color="orange">Rust SDK</Badge>
173+ <Badge color="orange">Rust AI Agent SDK</Badge>
61174
62175{ escape_mdx (info .docstring ) if info .docstring else "" }
63176
@@ -72,17 +185,19 @@ def generate_module_page(info, output_dir: Path, dry_run: bool = False) -> str:
72185 if info .classes :
73186 content += "## Types\n \n <CardGroup cols={2}>\n "
74187 for cls in info .classes :
188+ cls_title = friendly_title (cls .name , "class" )
75189 cls_desc = sanitize_description (cls .docstring ) or "Type definition."
76- content += f' <Card title="{ cls . name } " icon="brackets-curly" href="../classes/{ cls .name } ">\n '
190+ content += f' <Card title="{ cls_title } " icon="brackets-curly" href="../classes/{ cls .name } ">\n '
77191 content += f" { cls_desc } \n "
78192 content += " </Card>\n "
79193 content += "</CardGroup>\n \n "
80194
81195 if info .functions :
82196 content += "## Functions\n \n <CardGroup cols={2}>\n "
83197 for func in info .functions :
198+ func_title = friendly_title (func .name , "function" )
84199 func_desc = sanitize_description (func .docstring ) or "Function definition."
85- content += f' <Card title="{ func . name } () " icon="function" href="../functions/{ func .name } ">\n '
200+ content += f' <Card title="{ func_title } " icon="function" href="../functions/{ func .name } ">\n '
86201 content += f" { func_desc } \n "
87202 content += " </Card>\n "
88203 content += "</CardGroup>\n \n "
@@ -98,19 +213,25 @@ def generate_module_page(info, output_dir: Path, dry_run: bool = False) -> str:
98213def generate_class_page (cls , module_info , output_dir : Path , dry_run : bool = False ) -> str :
99214 """Generate a class/struct page."""
100215 short_name = module_info .short_name or module_info .name .split ('.' )[- 1 ]
101- desc = sanitize_description (cls .docstring ) or f"Class { cls .name } "
216+ module_title = friendly_title (short_name , "module" )
217+ title = friendly_title (cls .name , "class" )
218+ title_suffix = " • Rust AI Agent SDK"
219+ # Include original name in description for searchability
220+ base_desc = sanitize_description (cls .docstring ) if cls .docstring else f"{ cls .name } struct for Rust AI agents"
221+ desc = f"{ base_desc } " if cls .name in base_desc else f"{ cls .name } : { base_desc } "
102222
103223 content = f'''---
104- title: "{ cls .name } "
224+ title: "{ title } { title_suffix } "
225+ sidebarTitle: "{ title } "
105226description: "{ desc } "
106227icon: "brackets-curly"
107228---
108229
109230# { cls .name }
110231
111- > Defined in the [**{ short_name } **](../modules/{ short_name } ) module.
232+ > Defined in the [**{ module_title } **](../modules/{ short_name } ) module.
112233
113- <Badge color="orange">Rust SDK</Badge>
234+ <Badge color="orange">Rust AI Agent SDK</Badge>
114235
115236{ escape_mdx (cls .docstring ) if cls .docstring else "" }
116237
@@ -156,21 +277,27 @@ def generate_class_page(cls, module_info, output_dir: Path, dry_run: bool = Fals
156277def generate_function_page (func , module_info , output_dir : Path , dry_run : bool = False ) -> str :
157278 """Generate a function page."""
158279 short_name = module_info .short_name or module_info .name .split ('.' )[- 1 ]
159- desc = sanitize_description (func .docstring ) or f"Function { func .name } "
280+ module_title = friendly_title (short_name , "module" )
281+ title = friendly_title (func .name , "function" )
282+ title_suffix = " • Rust AI Agent SDK"
283+ # Include original name in description for searchability
284+ base_desc = sanitize_description (func .docstring ) if func .docstring else f"{ func .name } function for Rust AI agents"
285+ desc = f"{ base_desc } " if func .name in base_desc else f"{ func .name } : { base_desc } "
160286 async_prefix = "async " if hasattr (func , 'is_async' ) and func .is_async else ""
161287 ret_type = func .return_type if hasattr (func , 'return_type' ) and func .return_type else "()"
162288
163289 content = f'''---
164- title: "{ func .name } "
290+ title: "{ title } { title_suffix } "
291+ sidebarTitle: "{ title } "
165292description: "{ desc } "
166293icon: "function"
167294---
168295
169- # { func .name } ()
296+ # { func .name }
170297
171- > Defined in the [**{ short_name } **](../modules/{ short_name } ) module.
298+ > Defined in the [**{ module_title } **](../modules/{ short_name } ) module.
172299
173- <Badge color="orange">Rust SDK</Badge>
300+ <Badge color="orange">Rust AI Agent SDK</Badge>
174301
175302```rust
176303{ async_prefix } fn { func .name } ({ func .signature } ) -> { ret_type }
0 commit comments