@@ -95,8 +95,6 @@ def execute(self) -> None:
9595 if isinstance (endpoint_types , str ):
9696 endpoint_types = [endpoint_types ]
9797
98- task_type = task .defaults .get ("config" , {}).get ("type" , "" )
99-
10098 data .append (
10199 [
102100 task .name , # task
@@ -105,8 +103,8 @@ def execute(self) -> None:
105103 else endpoint_types , # endpoint_type
106104 task .harness , # harness
107105 task .container , # container
106+ getattr (task , "container_arch" , "" ) or "" , # arch
108107 task .description , # description
109- task_type , # type
110108 ]
111109 )
112110 else :
@@ -121,13 +119,17 @@ def execute(self) -> None:
121119 "endpoint_type" ,
122120 "harness" ,
123121 "container" ,
122+ "arch" ,
124123 "description" ,
125- "type" ,
126124 ]
127125 supported_benchmarks = []
128126 for task_data in data :
129- assert len (task_data ) == len (headers )
130- supported_benchmarks .append (dict (zip (headers , task_data )))
127+ if len (task_data ) < len (headers ):
128+ raise ValueError (
129+ f"Invalid task row shape: expected at least { len (headers )} columns, got { len (task_data )} "
130+ )
131+ # Backwards/forwards compat: allow extra columns and ignore them.
132+ supported_benchmarks .append (dict (zip (headers , task_data [: len (headers )])))
131133
132134 if self .json :
133135 print (json .dumps ({"tasks" : supported_benchmarks }, indent = 2 ))
@@ -140,6 +142,48 @@ def _print_table(self, tasks: list[dict]) -> None:
140142 print ("No tasks found." )
141143 return
142144
145+ def _truncate (s : str , max_len : int ) -> str :
146+ s = s or ""
147+ if max_len <= 0 :
148+ return ""
149+ if len (s ) <= max_len :
150+ return s
151+ if max_len <= 3 :
152+ return s [:max_len ]
153+ return s [: max_len - 3 ] + "..."
154+
155+ def _infer_arch (container : str , container_tasks : list [dict ]) -> str :
156+ # Prefer explicit arch from task IRs.
157+ for t in container_tasks :
158+ a = (t .get ("arch" ) or "" ).strip ()
159+ if a :
160+ return a
161+
162+ # Heuristic fallback: look for common suffixes in tag.
163+ c = (container or "" ).lower ()
164+ if "arm64" in c or "aarch64" in c :
165+ return "arm"
166+ if "amd64" in c or "x86_64" in c :
167+ return "amd"
168+ return "unknown"
169+
170+ def _infer_registry (container : str ) -> str :
171+ try :
172+ from nemo_evaluator_launcher .common .container_metadata .utils import (
173+ parse_container_image ,
174+ )
175+
176+ registry_type , _registry_url , _repo , _ref = parse_container_image (container )
177+ return str (registry_type )
178+ except Exception :
179+ # Best-effort fallback for unknown formats.
180+ c = (container or "" ).lower ()
181+ if "nvcr.io/" in c or c .startswith ("nvcr.io" ):
182+ return "nvcr"
183+ if "gitlab" in c :
184+ return "gitlab"
185+ return ""
186+
143187 # Group tasks by harness and container
144188 grouped = defaultdict (lambda : defaultdict (list ))
145189 for task in tasks :
@@ -156,73 +200,77 @@ def _print_table(self, tasks: list[dict]) -> None:
156200 if j > 0 :
157201 print () # Spacing between containers
158202
159- # Prepare task table first to get column widths
160- task_header = "task"
161203 rows = []
162204 for task in container_tasks :
163- task_name = task ["task" ]
164- endpoint_type = task ["endpoint_type" ]
165- task_type = task .get ("type" , "" )
166- description = task .get ("description" , "" )
167- # Format: task_name (endpoint_type, task_type) - first 30 chars...
168- description_preview = description [:30 ] if description else ""
169- if len (description ) > 30 :
170- description_preview += "..."
171-
172- # Build the display name
173- type_part = f"{ endpoint_type } "
174- if task_type :
175- type_part += f", { task_type } "
176- display_name = f"{ task_name } ({ type_part } )"
177- if description_preview :
178- display_name = f"{ display_name } - { description_preview } "
179- rows .append (display_name )
180-
181- # Sort tasks alphabetically for better readability
182- rows .sort ()
183-
184- # Calculate column width
185- max_task_width = (
186- max (len (task_header ), max (len (str (row )) for row in rows )) + 2
187- )
205+ rows .append (
206+ {
207+ "task" : str (task .get ("task" , "" )),
208+ "endpoint" : str (task .get ("endpoint_type" , "" )),
209+ "description" : str (task .get ("description" , "" )),
210+ }
211+ )
212+ rows .sort (key = lambda r : r ["task" ].lower ())
188213
189214 # Calculate required width for header content
190215 harness_line = f"harness: { harness } "
191216 container_line = f"container: { container } "
217+ arch_line = f"arch: { _infer_arch (container , container_tasks )} "
218+ registry_line = f"registry: { _infer_registry (container )} "
192219 header_content_width = (
193- max (len (harness_line ), len (container_line )) + 4
220+ max (len (harness_line ), len (container_line ), len (arch_line ), len (registry_line ))
221+ + 4
194222 ) # +4 for "| " and " |"
195223
196- # Use the larger of the two widths
197- table_width = max (max_task_width , header_content_width )
198-
199224 # Limit separator width to prevent overflow on small terminals
200225 # Use terminal width if available, otherwise cap at 120 characters
201226 import shutil
202227
203228 try :
204229 terminal_width = shutil .get_terminal_size ().columns
205- separator_width = min (
206- table_width , terminal_width - 2
207- ) # -2 for safety margin
230+ separator_width = min (terminal_width - 2 , 160 ) # -2 safety margin
208231 except Exception :
209232 # Fallback if terminal size can't be determined
210- separator_width = min (table_width , 120 )
233+ separator_width = 120
234+
235+ separator_width = max (separator_width , min (header_content_width , 160 ))
236+
237+ # Table columns (keep compact and stable).
238+ col_task = 36
239+ col_endpoint = 14
240+ sep = " "
241+ fixed = col_task + col_endpoint + len (sep ) * 2
242+ col_desc = max (20 , separator_width - fixed )
211243
212244 # Print combined header with harness and container info - colorized
213245 # Keys: magenta, Values: cyan (matching logging utils)
214246 print (bold ("=" * separator_width ))
215247 print (f"{ magenta ('harness:' )} { cyan (str (harness ))} " )
216248 print (f"{ magenta ('container:' )} { cyan (str (container ))} " )
249+ arch = _infer_arch (container , container_tasks )
250+ registry = _infer_registry (container )
251+ print (f"{ magenta ('arch:' )} { cyan (str (arch ))} " )
252+ if registry :
253+ print (f"{ magenta ('registry:' )} { cyan (str (registry ))} " )
217254
218255 # Print task table header separator
219- print (" " * table_width )
220- print (bold (f"{ task_header :<{table_width }} " ))
256+ print ()
257+ print (
258+ bold (
259+ f"{ 'task' :<{col_task }} { sep } "
260+ f"{ 'endpoint' :<{col_endpoint }} { sep } "
261+ f"{ 'description' :<{col_desc }} "
262+ )
263+ )
221264 print (bold ("-" * separator_width ))
222265
223266 # Print task rows - use grey for task descriptions
224- for row in rows :
225- print (f"{ grey (str (row )):<{table_width }} " )
267+ for r in rows :
268+ line = (
269+ f"{ _truncate (r ['task' ], col_task ):<{col_task }} { sep } "
270+ f"{ _truncate (r ['endpoint' ], col_endpoint ):<{col_endpoint }} { sep } "
271+ f"{ _truncate (r ['description' ], col_desc ):<{col_desc }} "
272+ )
273+ print (grey (line ))
226274
227275 print (bold ("-" * separator_width ))
228276 # Show task count - grey for count text
0 commit comments