11from __future__ import annotations
22
33import json
4+ import re
45import sys
56from functools import wraps
6- from typing import Any , Callable , Dict , List , Literal , TypeVar , Union
7+ from typing import Any , Callable , Dict , List , Literal , Sequence , TypeVar , Union
78
89import click
10+ from tabulate import tabulate
911
1012from together import Together
1113from together .error import InvalidRequestError
1214from together .types import DedicatedEndpoint , ListEndpoint
15+ from together .types .endpoints import HardwareWithStatus
1316
1417
1518def print_endpoint (
@@ -98,7 +101,7 @@ def endpoints(ctx: click.Context) -> None:
98101)
99102@click .option (
100103 "--gpu" ,
101- type = click .Choice (["h100" , "a100" , "l40" , "l40s" , "rtx-6000" ]),
104+ type = click .Choice (["b200" , "h200" , " h100" , "a100" , "l40" , "l40s" , "rtx-6000" ]),
102105 required = True ,
103106 help = "GPU type to use for inference" ,
104107)
@@ -161,6 +164,8 @@ def create(
161164 """Create a new dedicated inference endpoint."""
162165 # Map GPU types to their full hardware ID names
163166 gpu_map = {
167+ "b200" : "nvidia_b200_180gb_sxm" ,
168+ "h200" : "nvidia_h200_140gb_sxm" ,
164169 "h100" : "nvidia_h100_80gb_sxm" ,
165170 "a100" : "nvidia_a100_80gb_pcie" if gpu_count == 1 else "nvidia_a100_80gb_sxm" ,
166171 "l40" : "nvidia_l40" ,
@@ -184,12 +189,18 @@ def create(
184189 availability_zone = availability_zone ,
185190 )
186191 except InvalidRequestError as e :
187- print_api_error (e )
188- if "check the hardware api" in str (e ).lower ():
192+ if (
193+ "check the hardware api" in str (e .args [0 ]).lower ()
194+ or "invalid hardware provided" in str (e .args [0 ]).lower ()
195+ or "the selected configuration" in str (e .args [0 ]).lower ()
196+ ):
197+ click .secho ("Invalid hardware selected." , fg = "red" , err = True )
198+ click .echo ("\n Available hardware options:" )
189199 fetch_and_print_hardware_options (
190200 client = client , model = model , print_json = False , available = True
191201 )
192-
202+ else :
203+ print_api_error (e )
193204 sys .exit (1 )
194205
195206 # Print detailed information to stderr
@@ -256,28 +267,85 @@ def hardware(client: Together, model: str | None, json: bool, available: bool) -
256267 fetch_and_print_hardware_options (client , model , json , available )
257268
258269
270+ def _format_hardware_options (
271+ hardware_options : Sequence [HardwareWithStatus ],
272+ show_availability : bool = True ,
273+ ) -> None :
274+ """Print hardware options in a formatted table using tabulate."""
275+ if not hardware_options :
276+ click .echo (" No hardware options found." , err = True )
277+ return
278+
279+ display_list : List [Dict [str , Any ]] = []
280+
281+ for hw in hardware_options :
282+ data : Dict [str , Any ] = {
283+ "Hardware ID" : hw .id ,
284+ "GPU" : (
285+ re .sub (r"\-\d+[a-zA-Z][a-zA-Z]$" , "" , hw .specs .gpu_type )
286+ if hw .specs and hw .specs .gpu_type
287+ else "N/A"
288+ ),
289+ "Memory" : f"{ int (hw .specs .gpu_memory )} GB" if hw .specs else "N/A" ,
290+ "Count" : hw .specs .gpu_count if hw .specs else "N/A" ,
291+ "Price (per minute)" : (
292+ f"${ hw .pricing .cents_per_minute / 100 :.2f} " if hw .pricing else "N/A"
293+ ),
294+ }
295+
296+ if show_availability :
297+ status_display = "—"
298+ if hw .availability :
299+ status = hw .availability .status
300+ # Add visual indicators for status
301+ if status == "available" :
302+ status_display = click .style ("✓ available" , fg = "green" )
303+ elif status == "unavailable" :
304+ status_display = click .style ("✗ unavailable" , fg = "red" )
305+ else : # insufficient
306+ status_display = click .style ("⚠ insufficient" , fg = "yellow" )
307+ data ["Availability" ] = status_display
308+
309+ display_list .append (data )
310+
311+ click .echo (tabulate (display_list , headers = "keys" , numalign = "left" ))
312+
313+
259314def fetch_and_print_hardware_options (
260315 client : Together , model : str | None , print_json : bool , available : bool
261316) -> None :
262317 """Print hardware options for a model."""
263-
264- message = "Available hardware options:" if available else "All hardware options:"
265- click .echo (message , err = True )
266318 hardware_options = client .endpoints .list_hardware (model )
319+
267320 if available :
268321 hardware_options = [
269322 hardware
270323 for hardware in hardware_options
271324 if hardware .availability is not None
272325 and hardware .availability .status == "available"
273326 ]
327+ message = (
328+ f"Available hardware options for model '{ model } ':"
329+ if model
330+ else "Available hardware options:"
331+ )
332+ else :
333+ message = (
334+ f"Hardware options for model '{ model } ':"
335+ if model
336+ else "All hardware options:"
337+ )
338+
339+ click .echo (message , err = True )
340+ click .echo ("" , err = True )
274341
275342 if print_json :
276343 json_output = [hardware .model_dump () for hardware in hardware_options ]
277344 click .echo (json .dumps (json_output , indent = 2 ))
278345 else :
279- for hardware in hardware_options :
280- click .echo (f" { hardware .id } " , err = True )
346+ # Show availability column only when model is specified (availability info is only returned with model filter)
347+ show_availability = model is not None
348+ _format_hardware_options (hardware_options , show_availability = show_availability )
281349
282350
283351@endpoints .command ()
0 commit comments