1717import json
1818import os
1919import re
20+ import sys
21+ import time
2022import urllib .request
2123from pathlib import Path
2224
@@ -103,18 +105,49 @@ def _fetch_registry() -> dict:
103105 return data
104106
105107
106- def _fetch_icon_svg (agent_id : str ) -> str :
107- """Fetch and sanitize SVG icon from CDN."""
108+ def _fetch_icon_svg (agent_id : str , retries : int = 3 ) -> str | None :
109+ """Fetch and sanitize SVG icon from CDN.
110+
111+ Returns the sanitized SVG string, or None if all retries fail.
112+ """
108113 url = f"{ ICON_BASE_URL } /{ agent_id } .svg"
109- try :
110- svg = _make_request (url , timeout = 10 ).decode ("utf-8" )
111- return _sanitize_svg (svg )
112- except Exception as e :
113- print (f"Warning: Could not fetch icon for { agent_id } : { e } " )
114- return ""
114+ for attempt in range (1 , retries + 1 ):
115+ try :
116+ svg = _make_request (url , timeout = 10 ).decode ("utf-8" )
117+ return _sanitize_svg (svg )
118+ except Exception as e :
119+ print (f"Warning: Could not fetch icon for { agent_id } (attempt { attempt } /{ retries } ): { e } " )
120+ if attempt < retries :
121+ time .sleep (2 )
122+ return None
123+
124+
125+ def _fetch_all_icons (agents : list [dict ]) -> dict [str , str ]:
126+ """Fetch icons for all agents from the CDN.
127+
128+ Returns a dict mapping agent_id -> sanitized SVG string.
129+ Raises SystemExit if any icon fails to fetch after retries.
130+ """
131+ icons : dict [str , str ] = {}
132+ failed : list [str ] = []
133+
134+ for agent in agents :
135+ agent_id = agent .get ("id" , "-" )
136+ svg = _fetch_icon_svg (agent_id )
137+ if svg is None :
138+ failed .append (agent_id )
139+ else :
140+ icons [agent_id ] = svg
115141
142+ if failed :
143+ print (f"Error: Failed to fetch icons for { len (failed )} agent(s): { ', ' .join (failed )} " )
144+ print ("Aborting to prevent publishing docs with missing icons." )
145+ sys .exit (1 )
116146
117- def _render_agent_cards (agents : list [dict ]) -> str :
147+ return icons
148+
149+
150+ def _render_agent_cards (agents : list [dict ], icons : dict [str , str ]) -> str :
118151 """Render agent cards as MDX components."""
119152 # Sort agents by name
120153 agents = sorted (agents , key = lambda a : a .get ("name" , "" ).lower ())
@@ -126,7 +159,7 @@ def _render_agent_cards(agents: list[dict]) -> str:
126159 name = agent .get ("name" , agent_id )
127160 version = _escape_text (agent .get ("version" , "-" ))
128161 repository = agent .get ("repository" , "" )
129- icon_svg = _fetch_icon_svg (agent_id )
162+ icon_svg = icons . get (agent_id )
130163
131164 lines .append (" <Card" )
132165 lines .append (f' title="{ _escape_html (name )} "' )
@@ -158,16 +191,18 @@ def main() -> None:
158191 print ("Please create the template file first." )
159192 raise SystemExit (1 )
160193
161- # Fetch registry data
194+ # Phase 1: Fetch all data (registry + icons) — abort on any failure
162195 registry = _fetch_registry ()
163196 agents = registry .get ("agents" , [])
164197
165198 if not agents :
166199 print ("Warning: No agents found in registry" )
167200
168- # Generate output
201+ icons = _fetch_all_icons (agents )
202+
203+ # Phase 2: Render and write — only reached if all fetches succeeded
169204 template = TEMPLATE_PATH .read_text ()
170- cards = _render_agent_cards (agents )
205+ cards = _render_agent_cards (agents , icons )
171206 output = template .replace (PLACEHOLDER , cards )
172207
173208 # Write output
0 commit comments